요약(TL;DR)
Workspace Connect는 조직이 서로 분리된 YouViCo 워크스페이스 간에 프로젝트를 공유하면서도 데이터 격리와 세분화된 권한을 유지할 수 있게 해줍니다. 아키텍처는 테넌트 간 참조, 권한 필터가 적용된 공유 프로젝트 뷰, 그리고 감사 로깅(audit logging)을 사용합니다. 핵심 과제는 조직의 민감한 데이터를 노출하지 않으면서 읽기 전용 또는 협업 접근 권한을 허용하는 것이었습니다. 해결책은 공유 프로젝트 토큰, 프로젝트별 역할 기반 접근 제어(RBAC), 그리고 조직 단위의 거부(veto) 권한입니다.
문제: 사일로화된 팀들
서로 다른 회사의 두 크리에이티브 팀(에이전시와 브랜드)이 동일한 캠페인 영상을 함께 리뷰해야 합니다. 현재 이들은 각자 별도의 YouViCo 워크스페이스를 사용합니다. 에이전시 워크스페이스가 따로 있고, 브랜드 워크스페이스가 따로 있습니다. 이로 인해 다음과 같은 마찰이 발생합니다.
- 에이전시가 자신의 워크스페이스에 영상을 업로드합니다
- 브랜드는 자신의 워크스페이스에서 그 영상을 볼 수 없습니다
- 에이전시가 영상을 내보내고, 브랜드는 다시 자신의 워크스페이스에 업로드합니다
- 그 결과 동일한 파일이 두 벌 존재하게 됩니다
- 한쪽에서 수정해도 반대쪽과 동기화되지 않습니다
해결책: Workspace Connect는 각 팀의 데이터를 격리한 상태에서 워크스페이스 간 공유를 가능하게 합니다.
아키텍처: 브릿지를 가진 멀티 테넌트 구조
YouViCo의 핵심 모델은 워크스페이스 범위(scope) 기반입니다. 모든 프로젝트, 댓글, 사용자는 정확히 하나의 워크스페이스(조직)에 속합니다. Workspace Connect는 이 구조를 다음과 같이 연결합니다.
Organization A Workspace Organization B Workspace
┌─────────────────────┐ ┌─────────────────────┐
│ Project "Campaign" │ │ Project View of │
│ (Owner) │ │ "Campaign" │
│ │ │ (Read-only access) │
└────────┬────────────┘ └─────────────────────┘
│ Shared Token │
└──────────────────────┘
(Cross-workspace link)
핵심 아이디어는 데이터를 옮기는 것이 아니라, 권한 제어가 적용된 워크스페이스 간 참조(reference)만 만든다는 점입니다.
토큰 기반 공유
Organization A가 Organization B에 프로젝트를 공유하려 할 때, Workspace Connect 토큰을 생성합니다.
interface WorkspaceConnectToken {
id: string;
sourceWorkspaceId: string;
sourceProjectId: string;
targetWorkspaceId: string;
permissions: Permission[]; // ['view', 'comment', 'edit']
expiresAt: Date;
// Audit
createdBy: string;
createdAt: Date;
}
class WorkspaceConnectService {
async generateToken(
projectId: string,
targetWorkspaceId: string,
permissions: Permission[]
): Promise<string> {
const token = {
id: uuid(),
sourceWorkspaceId: currentWorkspace.id,
sourceProjectId: projectId,
targetWorkspaceId,
permissions,
expiresAt: addDays(now(), 90),
createdBy: currentUser.id,
createdAt: now()
};
await db.workspaceConnectTokens.insert(token);
return token.id;
}
}
Organization B는 이 토큰을 받아 자신의 워크스페이스 안에서 해당 프로젝트를 볼 수 있게 됩니다.
권한 적용
Organization B가 공유 프로젝트에 접근할 때, 권한 검사는 두 단계로 진행됩니다.
1단계: 조직 수준 거부(veto)
- Organization A는 언제든 토큰을 폐기(revoke)할 수 있습니다
- 토큰은 만료될 수 있습니다
- Organization B도 접근을 거부하거나 철회할 수 있습니다
2단계: 리소스 수준 권한
- 토큰이 ‘view’를 부여하면 사용자는 보기만 가능합니다
- 토큰이 ‘comment’를 부여하면 댓글은 작성하되 편집은 할 수 없습니다
- Organization B가 작성한 댓글은 Organization A에서도 볼 수 있습니다
class SharedProjectService {
async getProject(projectId: string, userId: string) {
// First: is this a shared project?
const sharedProject = await db.sharedProjects.get({
projectId,
targetWorkspaceId: currentWorkspace.id
});
if (!sharedProject) {
// Not shared, use normal access control
return this.getProjectInternal(projectId, userId);
}
// This is a shared project
const token = await db.workspaceConnectTokens.get(sharedProject.tokenId);
// Check 1: Token still valid?
if (token.expiresAt < now()) {
throw new Error('Shared project access expired');
}
// Check 2: Token revoked?
if (token.status === 'revoked') {
throw new Error('Shared project access revoked');
}
// Check 3: User in target workspace?
const userWorkspace = await db.users.getWorkspace(userId);
if (userWorkspace.id !== token.targetWorkspaceId) {
throw new Error('User not in target workspace');
}
// All checks passed - return project with permission filters
const project = await this.getProjectInternal(projectId, userId);
// Apply permission filters
return {
...project,
canEdit: token.permissions.includes('edit'),
canComment: token.permissions.includes('comment'),
canDelete: false // Never allow delete on shared projects
};
}
}
워크스페이스 간 댓글 처리
Organization B의 사용자가 공유 프로젝트에 댓글을 달면, 그 댓글은 다음 조건을 만족해야 합니다.
- 양쪽 조직 모두에서 보여야 합니다
- 올바른 사용자에게 귀속되어야 합니다
- 어떤 워크스페이스, 어떤 토큰을 통해 들어왔는지에 대한 감사 기록(audit trail)을 포함해야 합니다
class CommentService {
async createComment(
projectId: string,
frameNumber: number,
text: string,
userId: string
) {
// Get the shared project relationship
const sharedProject = await this.getSharedProjectIfAccessible(projectId, userId);
if (sharedProject) {
// User is from a different workspace
const comment = {
id: uuid(),
projectId,
frameNumber,
text,
authorId: userId,
authorWorkspaceId: sharedProject.targetWorkspaceId,
sourceWorkspaceId: sharedProject.sourceWorkspaceId,
isFromSharedWorkspace: true,
sharedViaTokenId: sharedProject.tokenId,
createdAt: now()
};
await db.comments.insert(comment);
// Audit log
await auditLog('shared_comment_created', {
projectId,
authorWorkspaceId: sharedProject.targetWorkspaceId,
tokenId: sharedProject.tokenId
});
} else {
// Normal comment from same workspace
const comment = { /* ... */ };
await db.comments.insert(comment);
}
}
}
데이터 격리: 무엇이 비공개로 남는가
Organization A가 Organization B에 프로젝트를 공유할 때 다음과 같이 구분됩니다.
공개되는 항목:
- 프로젝트 이름, 설명
- 영상 파일과 프레임
- 댓글(공유된 프로젝트에 한정)
- 메타데이터(영상 길이, 프레임레이트 등)
숨겨지는 항목:
- Organization A의 다른 프로젝트들
- Organization A의 팀원 목록
- Organization A의 결제 정보
- 공유되지 않은 프로젝트의 댓글
- 분석/성과 데이터
이 분리는 데이터베이스 쿼리 단계에서 강제됩니다. 공유 프로젝트에 대한 쿼리는 민감한 데이터를 명시적으로 필터링합니다.
접근 권한 폐기
Organization A는 언제든 즉시 접근 권한을 폐기할 수 있습니다.
async revokeAccess(tokenId: string) {
const token = await db.workspaceConnectTokens.get(tokenId);
// Mark token as revoked
await db.workspaceConnectTokens.update(tokenId, {
status: 'revoked',
revokedAt: now(),
revokedBy: currentUser.id
});
// Audit log
await auditLog('workspace_connect_revoked', {
tokenId,
sourceWorkspaceId: token.sourceWorkspaceId,
targetWorkspaceId: token.targetWorkspaceId,
revokedAt: now()
});
// Optional: notify Organization B
await notificationService.send(
targetWorkspaceId,
'Access to project revoked'
);
}
이 순간부터 Organization B는 접근 권한을 잃습니다. 모든 요청마다 검사되기 때문에 폐기는 즉시 적용됩니다.
감사 로그
모든 워크스페이스 간 작업은 로그로 남습니다.
SELECT action, source_workspace, target_workspace, action_time
FROM audit_log
WHERE action LIKE 'shared_%'
ORDER BY action_time DESC;
-- Output:
shared_comment_created Org A Org B 2026-03-28 14:23:15
shared_project_accessed Org B Org A 2026-03-28 14:22:45
workspace_connect_token_generated Org A Org B 2026-03-28 14:20:00
이 로그는 워크스페이스 경계를 넘나드는 접근에 대해 완전한 가시성을 제공합니다.
배운 점
-
토큰 기반 공유가 인증을 페더레이션(federation)하려는 시도보다 단순합니다.
-
여러 계층(조직, 리소스)에서 권한을 강제하는 것이 실수를 막아줍니다.
-
엔터프라이즈 보안에서 감사 로깅은 필수입니다. 고객은 자신의 데이터에 누가 접근했는지 정확히 알고 싶어 합니다.
-
폐기는 결국에 적용되는(eventual) 것이 아니라 즉시 적용되어야 합니다. 사용자는 즉각적인 접근 차단을 기대합니다.
-
데이터를 과하게 노출하지 마세요. 공유할 수 있다고 해서 모든 것을 노출해야 한다는 뜻은 아닙니다.
Workspace Connect는 YouViCo를 단일 조직 도구에서 협업 플랫폼으로 탈바꿈시켰습니다. 출시 이후 회사 간 워크플로우는 5배 증가했습니다.