Connecting a personal Google Drive / OneDrive fails when the user has no company:
psycopg2.errors.NotNullViolation: null value in column "company_id" of relation "chat_backend_driveconnection" violates not-null constraint
Rejecting the link with no_company is not the fix. Personal Drive / personal RAG must work for users who are not part of a company. Company is only required for business (company) Drive / RAG.
Parent: #42
Related: #46 (personal vs company workspace), #47–#49
Product model
Kind
Who
Company required?
Workspace
personal
any entitled user
No
personal DocumentWorkspace owned by user
company
company manager
Yes
company DocumentWorkspace
Solo / no-company users must be able to connect personal Google Drive or OneDrive and sync into personal RAG.
Sync / uploads for that path land in a personal workspace (user-scoped), not a company workspace
RAG chat for no-company users resolves that personal workspace (fail closed; no cross-tenant leak)
Company Drive (link_company_drive) still requires company + manager; reject clearly if missing
Suggested implementation
Schema
DriveConnection.company → null=True, blank=True
CheckConstraint: kind=company ⇒ company_id IS NOT NULL; kind=personal ⇒ user_id IS NOT NULL
Replace uniqueness with conditional uniques:
personal: (user, provider) where kind=personal
company: (company, provider) where kind=company
DocumentWorkspace: allow personal ownership — user FK (nullable) + company nullable; company workspaces keep company set / user null; personal keep user set / company null
Runtime
upsert_drive_connection: personal may have null company; company kind still requires user.company_id (else OAuthError)
ensure_personal_workspace(user) + sync: personal connection → personal WS; company connection → company WS
resolve_chat_company_scope / document list-upload: if user has no company → personal workspace (do not raise company_missing for personal RAG)
Keep stove-pipe: scope always keys retrieval on the resolved workspace_id
Tests
Personal Drive callback with user.company=NULL → 302 success, row with company_id=NULL, user_id set
Company Drive still rejects no-company / non-manager
Sync personal no-company connection creates docs on personal workspace
Chat/RAG scope for no-company user returns personal workspace (no company_missing)
Out of scope / follow-ups
Full multi-workspace retrieval (personal and company KB in one chat turn) — may stay under #46
FE copy for no_company on company connect only
Repro
User with company_id = NULL (entitled plan with allows_rag)
Connect personal Google Drive / OneDrive
Observe NotNullViolation (or wrong no_company rejection from the interim PR)
Anti-goals
Do not require inventing a fake company for personal Drive
Do not treat “reject no company” as closing this bug for personal connect
## Summary
Connecting a **personal** Google Drive / OneDrive fails when the user has no company:
```
psycopg2.errors.NotNullViolation: null value in column "company_id" of relation "chat_backend_driveconnection" violates not-null constraint
```
**Rejecting** the link with `no_company` is **not** the fix. Personal Drive / personal RAG must work for users who are **not** part of a company. Company is only required for **business** (company) Drive / RAG.
Parent: [#42](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/42)
Related: [#46](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/46) (personal vs company workspace), [#47](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/47)–[#49](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/49)
## Product model
| Kind | Who | Company required? | Workspace |
|------|-----|-------------------|-----------|
| `personal` | any entitled user | **No** | personal `DocumentWorkspace` owned by `user` |
| `company` | company manager | **Yes** | company `DocumentWorkspace` |
Solo / no-company users must be able to connect personal Google Drive or OneDrive and sync into **personal RAG**.
## Actual (bug)
- `DriveConnection.company` is NOT NULL
- `upsert_drive_connection` sets `company=user.company` → `NULL` → crash
- Sync / document APIs / chat tenant scope assume a company workspace (`ensure_company_workspace`), so even a nullable FK alone is incomplete
## Expected
1. Personal Drive OAuth (`intent=link_drive`) succeeds for users with `company_id=NULL`
2. Creates/updates `DriveConnection(kind=personal, user=<user>, company=NULL)`
3. Sync / uploads for that path land in a **personal** workspace (user-scoped), not a company workspace
4. RAG chat for no-company users resolves that personal workspace (fail closed; no cross-tenant leak)
5. Company Drive (`link_company_drive`) still requires company + manager; reject clearly if missing
## Suggested implementation
### Schema
- `DriveConnection.company` → `null=True, blank=True`
- CheckConstraint: `kind=company` ⇒ `company_id IS NOT NULL`; `kind=personal` ⇒ `user_id IS NOT NULL`
- Replace uniqueness with conditional uniques:
- personal: `(user, provider)` where `kind=personal`
- company: `(company, provider)` where `kind=company`
- `DocumentWorkspace`: allow personal ownership — `user` FK (nullable) + `company` nullable; company workspaces keep `company` set / `user` null; personal keep `user` set / `company` null
### Runtime
- `upsert_drive_connection`: personal may have null company; company kind still requires `user.company_id` (else `OAuthError`)
- `ensure_personal_workspace(user)` + sync: personal connection → personal WS; company connection → company WS
- `resolve_chat_company_scope` / document list-upload: if user has no company → personal workspace (do not raise `company_missing` for personal RAG)
- Keep stove-pipe: scope always keys retrieval on the resolved `workspace_id`
### Tests
- Personal Drive callback with `user.company=NULL` → 302 success, row with `company_id=NULL`, `user_id` set
- Company Drive still rejects no-company / non-manager
- Sync personal no-company connection creates docs on personal workspace
- Chat/RAG scope for no-company user returns personal workspace (no `company_missing`)
## Out of scope / follow-ups
- Full multi-workspace retrieval (personal **and** company KB in one chat turn) — may stay under [#46](https://git.aimloperations.com/ai_ml_operations/chat_backend/issues/46)
- FE copy for `no_company` on **company** connect only
## Repro
1. User with `company_id = NULL` (entitled plan with `allows_rag`)
2. Connect personal Google Drive / OneDrive
3. Observe NotNullViolation (or wrong `no_company` rejection from the interim PR)
## Anti-goals
- Do **not** require inventing a fake company for personal Drive
- Do **not** treat “reject no company” as closing this bug for personal connect
westfarn
changed title from DriveConnection upsert crashes: null company_id NotNullViolation on Google Drive link to Personal Drive/RAG must work without a company (null company_id)2026-08-02 03:38:16 -07:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Summary
Connecting a personal Google Drive / OneDrive fails when the user has no company:
Rejecting the link with
no_companyis not the fix. Personal Drive / personal RAG must work for users who are not part of a company. Company is only required for business (company) Drive / RAG.Parent: #42
Related: #46 (personal vs company workspace), #47–#49
Product model
personalDocumentWorkspaceowned byusercompanyDocumentWorkspaceSolo / no-company users must be able to connect personal Google Drive or OneDrive and sync into personal RAG.
Actual (bug)
DriveConnection.companyis NOT NULLupsert_drive_connectionsetscompany=user.company→NULL→ crashensure_company_workspace), so even a nullable FK alone is incompleteExpected
intent=link_drive) succeeds for users withcompany_id=NULLDriveConnection(kind=personal, user=<user>, company=NULL)link_company_drive) still requires company + manager; reject clearly if missingSuggested implementation
Schema
DriveConnection.company→null=True, blank=Truekind=company⇒company_id IS NOT NULL;kind=personal⇒user_id IS NOT NULL(user, provider)wherekind=personal(company, provider)wherekind=companyDocumentWorkspace: allow personal ownership —userFK (nullable) +companynullable; company workspaces keepcompanyset /usernull; personal keepuserset /companynullRuntime
upsert_drive_connection: personal may have null company; company kind still requiresuser.company_id(elseOAuthError)ensure_personal_workspace(user)+ sync: personal connection → personal WS; company connection → company WSresolve_chat_company_scope/ document list-upload: if user has no company → personal workspace (do not raisecompany_missingfor personal RAG)workspace_idTests
user.company=NULL→ 302 success, row withcompany_id=NULL,user_idsetcompany_missing)Out of scope / follow-ups
no_companyon company connect onlyRepro
company_id = NULL(entitled plan withallows_rag)no_companyrejection from the interim PR)Anti-goals
DriveConnection upsert crashes: null company_id NotNullViolation on Google Drive linkto Personal Drive/RAG must work without a company (null company_id)