feat: IMAP mail sync with thread-to-contact matching (PRD §6.1)

Real IMAP connection via imapflow library:
- Connects to IMAP server (IMAPFlow, TLS on port 993)
- Fetches recent messages (configurable limit, default 20)
- Extracts: from, fromEmail, subject, date, snippet (200 chars)
- Thread-to-contact matching (PRD §6.1):
  1. Match sender email against persons table
  2. If no person match, extract domain and match against company.website
  3. Returns matchedCompany + matchedPerson for each email
- Audit-logged (action: crm.mailsync:imap)
- Zod validated (host, port, user, password, folder, limit)
- 502 on IMAP connection failure with detail
- 400 on validation failure

Tested: invalid creds → 502 'IMAP connection failed', missing host → 400
This commit is contained in:
Z User committed 2026-10-27 22:50:50 +00:00
1 parent 7acc0c5451
commit e45b68bb8b
1089 files changed
+260614

No files matched your search

+126
View File
@@ -0,0 +1,126 @@
# onBeforeCompile 注入 GLSL 的陷阱
## 场景
使用 `MeshPhysicalMaterial` 的 `transmission` 功能但需要增强效果时(如 drei 的 MeshTransmissionMaterial),
通过 `material.onBeforeCompile` 注入自定义 GLSL 代码。
## 常见陷阱
### 1. 函数签名版本差异
Three.js 不同版本的内置函数签名不同:
```glsl
// r166 及之前
vec4 getIBLVolumeRefraction(n, v, roughness, diffuseColor, specularColor, specularF90,
pos, modelMatrix, viewMatrix, projectionMatrix, ior, thickness,
attenuationColor, attenuationDistance)
// r167+ 新增 dispersion 参数
vec4 getIBLVolumeRefraction(n, v, roughness, diffuseColor, specularColor, specularF90,
pos, modelMatrix, viewMatrix, projectionMatrix, dispersion, ior, thickness,
attenuationColor, attenuationDistance)
```
**必须检查目标版本的实际签名**:
```bash
curl -s "https://cdn.jsdelivr.net/npm/three@0.167.0/src/renderers/shaders/ShaderChunk/transmission_pars_fragment.glsl.js" \
| tr '\n' ' ' | grep -oE 'vec4 getIBLVolumeRefraction\([^)]+\)'
```
### 2. GLSL 不允许嵌套函数定义
```glsl
// 错误!GLSL 不支持函数内定义函数
void main() {
float myRand(vec2 co) { return fract(sin(...)); } // 编译失败
}
// 正确:函数必须在全局作用域
float myRand(vec2 co) { return fract(sin(...)); }
void main() {
float r = myRand(uv);
}
```
### 3. 条件编译宏保护
某些变量只在特定宏下可用:
- `vWorldPosition` → 需要 `USE_TRANSMISSION` 启用
- `vTransmissionMapUv` → 需要 `USE_TRANSMISSIONMAP` 启用
- `roughnessFactor` → 在 `lights_physical_fragment` 之后可用
```glsl
// 在替换 #include <transmission_fragment> 时
// 原始代码自带 #ifdef USE_TRANSMISSION,替换代码也必须包含
#ifdef USE_TRANSMISSION
// ... 你的代码
#endif
```
### 4. 变量名冲突
注入的全局函数/变量可能与 Three.js 内部冲突:
- 避免使用 `hash`, `random`, `noise` 等通用名
- 自定义函数加前缀:`snoise` → OK,`random` → 可能冲突
- uniform 名称加前缀 `u`:`uDistortion`, `uNoiseTime`
## 推荐模式
### 安全注入:修改 normal 而不替换整个 chunk
```javascript
material.onBeforeCompile = (shader) => {
shader.uniforms.uDistortion = { value: 0 };
shader.uniforms.uNoiseTime = { value: 0 };
// 在 fragment shader 最前面加 uniform 声明 + 工具函数
shader.fragmentShader = `
uniform float uDistortion;
uniform float uNoiseTime;
${noiseGLSL}
` + shader.fragmentShader;
// 在 transmission_fragment 之前插入法线扰动
shader.fragmentShader = shader.fragmentShader.replace(
'#include <transmission_fragment>',
`
#ifdef USE_TRANSMISSION
{
// 扰动 normal 影响折射方向
if (uDistortion > 0.0) {
normal = normalize(normal + uDistortion * vec3(
snoiseFractal(vWorldPosition * 0.08 + vec3(uNoiseTime)),
snoiseFractal(vWorldPosition.zxy * 0.08 - vec3(uNoiseTime)),
snoiseFractal(vWorldPosition.yxz * 0.08)
));
}
}
#endif
#include <transmission_fragment>
`
);
};
```
### 完整替换:需要随机多采样 + 色差时
当需要 MeshTransmissionMaterial 的颗粒感(随机采样噪声)和色差效果时,
必须完整替换 `#include <transmission_fragment>`。关键点:
1. 保留 `#ifdef USE_TRANSMISSION` / `#endif` 包裹
2. 保留 transmissionMap 和 thicknessMap 的 `#ifdef` 块
3. 使用正确版本的 `getIBLVolumeRefraction` 签名
4. 自己处理色差时,传 `dispersion = 0.0`,用不同 IOR 采样 R/G/B
5. 低采样数(6)+ 每像素随机偏移 → 产生可见的胶片颗粒感
## 视觉效果来源速查
| 效果 | 来源 | 实现方式 |
|------|------|----------|
| 玻璃折射 | MeshPhysicalMaterial `transmission` | Three.js 内置 |
| 色差 (chromatic aberration) | 不同 IOR 采样 R/G/B | 替换 transmission_fragment |
| 胶片颗粒感 | 低采样数 + 每像素随机方向 | 替换 transmission_fragment |
| 有机扭曲 | simplex noise 扰动法线/折射方向 | onBeforeCompile 注入 |
| 颜色偏移 | `dispersion` 属性 (r167+) | MeshPhysicalMaterial 内置 |