[CL-OBJECT-ACCESS-SLUG] objectAccess: accept slug + id (fix AI Анализ "Object not found") #201
Closed
andrei
wants to merge 1 commit from
fix/cl-object-access-slug into master
pull from: fix/cl-object-access-slug
merge into: europa-tech-srl:master
europa-tech-srl:master
europa-tech-srl:agent-fullstack/pix-8339
europa-tech-srl:agent-fullstack/pix-8023
europa-tech-srl:agent-fullstack/pix-8030
europa-tech-srl:agent-cto/pix-8429
europa-tech-srl:agent-cto/pix-8422
europa-tech-srl:agent-fullstack/pix-7915
europa-tech-srl:main
europa-tech-srl:agent-fullstack/pix-7993
europa-tech-srl:agent-cto/pix-8433
europa-tech-srl:agent-cto/pix-7844-rebase
europa-tech-srl:fix/pix-7749-sanitizer-export
europa-tech-srl:agent-fullstack/pix-7749
europa-tech-srl:fix/cabinet-light-theme-contrast
europa-tech-srl:fix/claude-w10-g2-csp-inject
europa-tech-srl:feature/claude-cl-mojibake-objects-badge
europa-tech-srl:fix/pix-8381-bridge-lz-disabled
europa-tech-srl:agent-fullstack/pix-8170
europa-tech-srl:agent-cto/pix-8371
europa-tech-srl:agent-fullstack/pix-8072
europa-tech-srl:agent-fullstack/pix-8313
europa-tech-srl:agent-fullstack/pix-8307
europa-tech-srl:agent-fullstack/pix-7388-landing-apr-followup
europa-tech-srl:agent-cto/pix-8289
europa-tech-srl:agent-fullstack/pix-8284
europa-tech-srl:agent-fullstack/pix-8259
europa-tech-srl:agent-fullstack/pix-8239
europa-tech-srl:agent-fullstack/pix-7388-incomestory-followup
europa-tech-srl:agent-fullstack/pix-8220
europa-tech-srl:agent-fullstack/pix-8007
europa-tech-srl:agent-fullstack/pix-8190
europa-tech-srl:feat/PIX-8170-soften-blog-income-claims
europa-tech-srl:agent-fullstack/pix-8164
europa-tech-srl:agent-fullstack/pix-7388-roomexplorer-followup
europa-tech-srl:fix/claude-cl-redis-adapter-mock-on
europa-tech-srl:seo/homepage-title-ru
europa-tech-srl:agent-fullstack/pix-8105
europa-tech-srl:agent-fullstack/pix-8143
europa-tech-srl:agent-fullstack/pix-8135
europa-tech-srl:master-deploy-pix8054
europa-tech-srl:agent-fullstack/pix-7850
europa-tech-srl:fix/pix-8054-local-history-warning
europa-tech-srl:fix/pix-8054-local-hetzner-deploy
europa-tech-srl:agent-fullstack/pix-7939
europa-tech-srl:agent-fullstack/pix-7916
europa-tech-srl:fix/pix-8054-deploy-migration-history
europa-tech-srl:agent-fullstack/pix-7901
europa-tech-srl:agent-fullstack/pix-7884
europa-tech-srl:feat/PIX-7860-public-copy-safety
europa-tech-srl:agent-fullstack/pix-7857
europa-tech-srl:agent-devops/pix-8020
europa-tech-srl:agent-fullstack/pix-7844
europa-tech-srl:agent-fullstack/pix-7839
europa-tech-srl:agent-fullstack/pix-7687
europa-tech-srl:agent-fullstack/pix-7838
europa-tech-srl:agent-fullstack/pix-7388
europa-tech-srl:agent-cto/pix-7814
europa-tech-srl:agent-fullstack/pix-7808
europa-tech-srl:agent-devops/pix-7974
europa-tech-srl:agent-fullstack/pix-7510
europa-tech-srl:agent-fullstack/pix-7694
europa-tech-srl:agent-cto/pix-7900
europa-tech-srl:feature/claude-cl-archlint-tail-20260607
europa-tech-srl:fix/pix-7734-seo-price-live
europa-tech-srl:agent-fullstack/pix-7791
europa-tech-srl:agent-fullstack/pix-7724
europa-tech-srl:agent-cto/pix-7815
europa-tech-srl:agent-fullstack/pix-7771
europa-tech-srl:agent-fullstack/pix-7767
europa-tech-srl:agent-fullstack/pix-7766
europa-tech-srl:agent-cto/pix-7726
europa-tech-srl:agent-fullstack/pix-7734
europa-tech-srl:agent-cto/pix-7532
europa-tech-srl:agent-fullstack/pix-7713
europa-tech-srl:agent-fullstack/pix-7436
europa-tech-srl:pix-7201-apr-hero-fix-v2
europa-tech-srl:feat/PIX-7409-health-limiter
europa-tech-srl:agent-fullstack/pix-7376
europa-tech-srl:agent-fullstack/pix-7650
europa-tech-srl:agent-cto/pix-7202
europa-tech-srl:agent-fullstack/pix-7623
europa-tech-srl:fix/pix-7613-blog-disclaimers
europa-tech-srl:agent-fullstack/pix-7597
europa-tech-srl:agent-fullstack/pix-7578
europa-tech-srl:agent-cto/pix-7655
europa-tech-srl:agent-fullstack/pix-7527
europa-tech-srl:agent-devops/pix-7612
europa-tech-srl:agent-fullstack/pix-7540
europa-tech-srl:agent-fullstack/pix-7539
europa-tech-srl:agent-cto/pix-7494
europa-tech-srl:agent-cto/pix-7495
europa-tech-srl:agent-fullstack/pix-7507
europa-tech-srl:feature/claude-audit-wave4-admin-2fa
europa-tech-srl:agent-fullstack/pix-7304
europa-tech-srl:agent-fullstack/pix-7337
europa-tech-srl:agent-fullstack/pix-7344
europa-tech-srl:agent-fullstack/pix-7305
europa-tech-srl:agent-fullstack/pix-7317
europa-tech-srl:agent-cto/pix-6804
europa-tech-srl:pix-7514-prisma-env-path-clean
europa-tech-srl:agent-fullstack/pix-7360
europa-tech-srl:agent-fullstack/pix-7425
europa-tech-srl:cto/pix-7505-clean
europa-tech-srl:agent-fullstack/pix-7400-compliance-copy-v2
europa-tech-srl:pix-7201-apr-hero-fix-clean
europa-tech-srl:agent-fullstack/pix-7416
europa-tech-srl:agent-fullstack/pix-7409
europa-tech-srl:agent-fullstack/pix-7400-compliance-copy
europa-tech-srl:agent-fullstack/pix-7318-investor-copy-followup
europa-tech-srl:agent-cto/pix-7201
europa-tech-srl:agent-27a1dc8e-9e87-48b3-8ab7-0603a2d5374a/pix-6398
europa-tech-srl:agent-27a1dc8e-9e87-48b3-8ab7-0603a2d5374a/pix-7121
europa-tech-srl:agent-cto/pix-6834
europa-tech-srl:agent-cto/pix-6895
europa-tech-srl:agent-fullstack/pix-7389
europa-tech-srl:agent-fullstack/pix-7399-delivery
europa-tech-srl:agent-fullstack/pix-7398
europa-tech-srl:agent-fullstack/pix-7397
europa-tech-srl:agent-cto/pix-7443
europa-tech-srl:agent-fullstack/pix-7306
europa-tech-srl:agent-fullstack/pix-7364-recover-7001
europa-tech-srl:agent-fullstack/pix-7318
europa-tech-srl:agent-cto/pix-7315
europa-tech-srl:agent-devops/pix-7307
europa-tech-srl:agent-cto/pix-7288-recover-pix-6734
europa-tech-srl:agent-fullstack/pix-7268
europa-tech-srl:agent-fullstack/pix-7266-recover-7172
europa-tech-srl:agent-fullstack/pix-7266-recover-7010
europa-tech-srl:agent-devops/pix-7262
europa-tech-srl:agent-cto/pix-7196
europa-tech-srl:feature/pix-7198-public-object-detail
europa-tech-srl:agent-cto/pix-7195
europa-tech-srl:agent-27a1dc8e-9e87-48b3-8ab7-0603a2d5374a/pix-7184
europa-tech-srl:agent-compliance/pix-7173
europa-tech-srl:agent-cto/pix-7178
europa-tech-srl:agent-cto/pix-7138
europa-tech-srl:agent-cto/pix-7143
europa-tech-srl:agent-cto/pix-7133
europa-tech-srl:feature/claude-marketing-copy-fix
europa-tech-srl:agent-cto/pix-7109
europa-tech-srl:agent-ir-investor-relations/pix-7108
europa-tech-srl:agent-cto/pix-7097
europa-tech-srl:agent-fullstack/pix-7011
europa-tech-srl:agent-compliance/pix-7088
europa-tech-srl:chore/groq-key-rotation
europa-tech-srl:compliance-pix-6561-final
europa-tech-srl:agent-fullstack/pix-7045
europa-tech-srl:agent-cto/pix-7040
europa-tech-srl:agent-cto/pix-7039
europa-tech-srl:agent-cto/pix-7038
europa-tech-srl:agent-cto/pix-7032
europa-tech-srl:agent-cto/pix-7022
europa-tech-srl:agent-cto/pix-7014
europa-tech-srl:agent-fullstack/pix-6963
europa-tech-srl:agent-cto/pix-6950
europa-tech-srl:fix/audit-20260530-m4-m8
europa-tech-srl:fix/audit-20260530-m3-seo
europa-tech-srl:fix/pix-tma-admin-auth-friendly
europa-tech-srl:feature/claude-pix-6734-apr-disclaimer
europa-tech-srl:agent-cto/pix-6949
europa-tech-srl:agent-cto/pix-6940
europa-tech-srl:fix/pix-6584-invest-meta-mica-claim
europa-tech-srl:fix/pix-6445-i18n-landing-overclaim-all-langs
europa-tech-srl:agent-cto/pix-6685
europa-tech-srl:agent-cto/pix-6658
europa-tech-srl:agent-cto/pix-6650
europa-tech-srl:agent-fullstack/pix-6980
europa-tech-srl:agent-ir-investor-relations/pix-6335
europa-tech-srl:agent-cto/pix-6967
europa-tech-srl:agent-fullstack/pix-6976
europa-tech-srl:agent-cto/pix-6977
europa-tech-srl:agent-cto/pix-6850
europa-tech-srl:agent-cto/pix-6953
europa-tech-srl:agent-cto/pix-6918
europa-tech-srl:agent-cto/pix-6960
europa-tech-srl:agent-cto/pix-6962
europa-tech-srl:agent-fullstack/pix-6961
europa-tech-srl:agent-fullstack/pix-6624
europa-tech-srl:agent-fullstack/pix-6743
europa-tech-srl:agent-cto/pix-6734
europa-tech-srl:agent-devops/03c4c823-9519-4b40-b4a3-4bc063059445
europa-tech-srl:agent-fullstack/pix-6866
europa-tech-srl:agent-cto/pix-6891
europa-tech-srl:fix/PIX-4255-db-restore-readiness
europa-tech-srl:agent-cto/pix-6703
europa-tech-srl:agent-compliance/pix-6577
europa-tech-srl:agent-cto/pix-6867
europa-tech-srl:agent-fullstack/pix-6825
europa-tech-srl:agent-cto/pix-6832
europa-tech-srl:agent-cto/pix-6805
europa-tech-srl:agent-fullstack/pix-6690
europa-tech-srl:agent-fullstack/pix-6744
europa-tech-srl:agent-cto/pix-6742
europa-tech-srl:agent-fullstack/pix-6709
europa-tech-srl:agent-cto/pix-6675
europa-tech-srl:agent-fullstack/pix-6710
europa-tech-srl:agent-fullstack/pix-6659
europa-tech-srl:agent-cto/pix-6664
europa-tech-srl:agent-cto/pix-6678
europa-tech-srl:agent-cto/pix-6642
europa-tech-srl:agent-fullstack/pix-6618
europa-tech-srl:agent-fullstack/pix-6639
europa-tech-srl:codex/obj-id-static-redirect-20260604
europa-tech-srl:agent-cto/pix-6648
europa-tech-srl:agent-cto/pix-6623
europa-tech-srl:agent-cto/pix-6632
europa-tech-srl:agent-cto/pix-6602
europa-tech-srl:agent-cto/pix-6634
europa-tech-srl:agent-fullstack/pix-6607
europa-tech-srl:agent-cto/pix-6613
europa-tech-srl:agent-cto/pix-6601
europa-tech-srl:agent-cto/pix-6570
europa-tech-srl:agent-cto/pix-6554
europa-tech-srl:agent-cto/pix-6553
europa-tech-srl:agent-cto/pix-6540
europa-tech-srl:agent-cto/pix-6542
europa-tech-srl:agent-cto/pix-6897
europa-tech-srl:fix/pix-6445-index-html-overclaim
europa-tech-srl:agent-ir-investor-relations/pix-6494
europa-tech-srl:agent-ir-investor-relations/pix-6478
europa-tech-srl:feature/pix-6445-compliance-sanitizer
europa-tech-srl:agent-cmo/pix-6407
europa-tech-srl:feature/tg-notify-deploy-integration
europa-tech-srl:cto/pix-6373-prod
europa-tech-srl:agent-ir-investor-relations/pix-6353
europa-tech-srl:agent
europa-tech-srl:fix/pix-6193-contract-info
europa-tech-srl:feat/pix-6076-public-compliance-copy
europa-tech-srl:fix/prod-pm2-memory-guard
No reviewers
Labels
Clear labels
No items
No labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set.
Reference
europa-tech-srl/europatech!201
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/cl-object-access-slug"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что сделано
Изменил
api/src/services/objectAccess.service.ts:findObjectByIdOrSlug(idOrSlug)—prisma.propertyObject.findFirst({ where: { OR: [{ id }, { slug }] }, select: { id, status } }). Один query вместо двух.assertObjectAccessible(idOrSlug, userId?)— теперь принимает slug ИЛИ id, использует resolved каноническийobject.idдляhasObjectOwnershipAccess(без этого rooms relationroom: { objectId }ищет по slug → false → ownership denied).assertObjectPublic(idOrSlug)— то же.{ status }(не вся prisma row) — preserve API shape, не ломает existing callers.(object) => object.idвgetPublicVisibleObjectIds— добавил explicit type{ id: string }.Также добавил
api/src/services/__tests__/objectAccess.service.test.ts— 8 vitest cases: slug→id resolved, canonical id directly, 404 on miss, ownership grants for non-public statuses, ownership deny throws, public path, non-public-status rejected, slug-not-found.Зачем
Live evidence prod (CEO репорт скриншот #2):
CEO открыл
/objects/hotel-baistrocchi-wellness-longevity-center/passport, в AI Анализ панели нажал «Обновить анализ» → 2× toast «Object not found». Анализ уже отображался (score 53/100), значит GET/api/analysis/<slug>работал (черезresolveObjectIdвpropertyAnalysis/analysis.ts). Но POST/api/analysis/<slug>/generate→generateAnalysisUsercontroller →assertObjectAccessible(slug, userId)→prisma.findUnique({where:{id:slug}})→ null → AppError 404.Тот же баг ломал:
income.controller(assetTabAccessчерезassertObjectAccessible)requireObjectAccessmiddleware (использует обе функции)dao.routes(assertObjectPublic)yieldDistribution.routes(dynamic importassertObjectAccessible)Все эти endpoints возвращали 404 если controller получал slug, что для public passport URL — норма.
Fix в одной точке (objectAccess.service) автоматически чинит весь импакт-кластер.
План тестирования
npx vitest run src/services/__tests__/objectAccess.service.test.ts— 8/8 PASSnpx vitest run src/services/__tests__/objectAccess.service.test.ts src/controllers/income.controller.test.ts src/services/analytics.service.test.ts— 38/38 PASS (regression-safe для existing callers через mock{status:'ACTIVE'}return shape)npx tsc --noEmit— clean (наш файл + bonus pre-existing TS7006 closed)npx eslint src/services/objectAccess.service.ts src/services/__tests__/objectAccess.service.test.ts --max-warnings 0— clean (exit=0)После merge + deploy через
bash scripts/deploy.sh:/api/analysis/hotel-baistrocchi-wellness-longevity-center/generateдолжен вернуть 201 (не 404).Где могу ошибаться
object(полная findUnique row) на{ status }. Все callers (8 мест по grep) деструктурируют как{ status }или игнорируют return — проверил vitest 38/38 проходит, в т.ч. income.controller.test ожидает{ status: 'ACTIVE' }. OK.hasObjectOwnershipAccess(userId, canonical_id)— теперь использует resolved id. Тестируется в новом vitest case (mock проверяетroom: { objectId: 'obj-002' }). Backward-compat: callers вне service используют только status, не объект.Root cause: assertObjectAccessible + assertObjectPublic used prisma.findUnique({where:{id}}) which rejects slug. analysis.controller generateAnalysisUser passes raw req.params.objectId (slug for public passport URLs) -> AppError 404 -> "Object not found" toast on CEO browse of /objects/<slug>/passport "Обновить анализ" button. Same pattern was breaking: - analysis.controller (generateAnalysisUser) - income.controller (assetTabAccess) - requireObjectAccess middleware - dao.routes - yieldDistribution.routes Fix: - Replace findUnique({where:{id}}) with findFirst({where:{OR:[{id},{slug}]}}) in single shared helper findObjectByIdOrSlug. - assertObjectAccessible + assertObjectPublic now resolve slug to canonical id before ownership lookup (hasObjectOwnershipAccess uses canonical id, not raw slug, so room: {objectId} relation matches). - Return narrowed {status} only (not the prisma row) to preserve original API. - Boy Scout: fixed pre-existing TS7006 in getPublicVisibleObjectIds map callback. Tests: 8 new vitest cases cover slug-resolved-to-id, canonical-id, 404 on miss, ownership-grants-for-non-public, ownership-deny-throws, public path, non-public-status-rejected, slug-not-found. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>Pull request closed