Inbox Agent Implementation Architecture and Repository Structure

1. Purpose

This document defines the recommended application code organization, repository structure, module boundaries, dependency direction, naming conventions, provider adapter layout, testing organization, worker organization, database organization, and implementation guardrails for Inbox Agent.

The goal is to provide a repository structure that:


2. Repository Philosophy

Use:

ONE REPOSITORY
+
CLEAR DOMAIN BOUNDARIES
+
MULTIPLE RUNTIME ENTRY POINTS

rather than many repositories initially.

The repository should behave like a modular monolith.


3. Recommended Repository Shape

inbox-agent/
├── apps/
│   ├── web/
│   └── workers/
│
├── packages/
│   ├── domain/
│   ├── application/
│   ├── api-contracts/
│   ├── providers/
│   ├── security/
│   ├── ai/
│   ├── persistence/
│   ├── jobs/
│   ├── observability/
│   ├── config/
│   └── testing/
│
├── database/
│   ├── migrations/
│   ├── seeds/
│   └── scripts/
│
├── infrastructure/
│   ├── environments/
│   ├── workers/
│   ├── storage/
│   └── monitoring/
│
├── tests/
│   ├── e2e/
│   ├── security/
│   ├── provider-contracts/
│   ├── ai-evals/
│   └── migration/
│
├── fixtures/
│   ├── mail/
│   ├── providers/
│   ├── security/
│   └── migration/
│
├── docs/
│   ├── requirements/
│   ├── architecture/
│   ├── decisions/
│   ├── operations/
│   └── runbooks/
│
├── scripts/
│
├── .github/
│   └── workflows/
│
└── README.md

4. Monorepo Tooling

A JavaScript/TypeScript workspace should support:

Shared types
Shared lint rules
Shared test utilities
Incremental builds
Dependency-aware CI

Exact workspace technology may be selected during implementation.

Examples include npm, pnpm, or equivalent workspace tooling.

Do not select tooling solely because it is fashionable; prioritize reliability and Cursor/tooling compatibility.


5. apps/web

apps/web contains the Next.js application.

Responsibilities:

React UI
Routes
Server/client presentation concerns
Authentication entry points
API transport adapters where colocated
OAuth callback endpoints
Webhook ingress endpoints

It should NOT contain the core business rules.


6. Web Directory Example

apps/web/
├── app/
│   ├── (authenticated)/
│   │   ├── home/
│   │   ├── needs-me/
│   │   ├── respond/
│   │   ├── waiting/
│   │   ├── security/
│   │   ├── search/
│   │   ├── rules/
│   │   ├── identity/
│   │   ├── migration/
│   │   └── settings/
│   ├── api/
│   └── auth/
│
├── components/
├── features/
├── hooks/
├── lib/
└── tests/

7. Feature-Oriented UI Organization

UI features should preferably group:

Components
Queries
Mutations
View models
Feature-specific hooks

around product capabilities.

Example:

features/waiting/
features/security-review/
features/rules/

Avoid a giant global components folder containing domain logic.


8. apps/workers

Worker runtime entry points live here.

Example:

apps/workers/
├── src/
│   ├── sync-worker.ts
│   ├── mail-processing-worker.ts
│   ├── command-worker.ts
│   ├── security-worker.ts
│   ├── ai-worker.ts
│   ├── migration-worker.ts
│   ├── reconciliation-worker.ts
│   └── maintenance-worker.ts

Workers should compose shared packages rather than duplicate business logic.


9. Worker Responsibilities

Workers are runtime hosts.

They should NOT contain domain implementation beyond orchestration/bootstrap.

Example:

Worker receives job
→ invokes Application Service
→ Application Service invokes Domain/Adapter

10. packages/domain

This is the core provider-independent domain model.

Contains:

Entities
Value objects
Enums
Domain services
Domain invariants
State transition logic

11. Domain Must Not Depend On

packages/domain should not import:

Next.js
Microsoft Graph SDK
Google APIs
IMAP library
PostgreSQL client
AI SDK
Queue SDK
Vercel SDK

This is a critical dependency rule.


12. Domain Module Structure

Example:

packages/domain/src/
├── mail/
├── conversations/
├── attention/
├── identities/
├── rules/
├── learning/
├── security/
├── approvals/
├── commands/
├── migration/
├── projects/
└── shared/

13. Logical Message Model

The authoritative implementation must distinguish:

MailMessage
Logical message/content identity

MessageInstance
Physical provider copy

Suggested domain structure:

domain/mail/
├── mail-message.ts
├── message-instance.ts
├── recipient.ts
├── attachment.ts
├── conversation.ts
└── provenance.ts

14. Provider Independence

The domain may expose:

MailAccount
MailIdentity
MailMessage
MessageInstance

but must not expose concepts such as:

GmailMessage
GraphMessage
IMAPMessage

outside provider modules.


15. packages/application

Contains use cases and application services.

Responsibilities:

Queries
Commands
Workflow orchestration
Authorization coordination
Policy evaluation
Service transactions
Event publication

16. Application Module Example

packages/application/src/
├── mail/
│   ├── get-message.ts
│   ├── archive-message.ts
│   └── search-mail.ts
├── conversations/
├── attention/
├── rules/
├── security/
├── approvals/
├── migration/
├── identity/
├── providers/
└── system/

17. Application Depends On Interfaces

Application services should depend on interfaces such as:

MailRepository
ConversationRepository
ProviderAdapter
JobQueue
AuditWriter
SecurityScanner
ModelGateway

Concrete implementations belong elsewhere.


18. packages/api-contracts

Contains transport-independent DTOs and schemas for:

Web API
Future iOS API
Agent tools
Webhook-normalized commands

Possible contents:

Request DTOs
Response DTOs
Error contracts
Validation schemas
OpenAPI generation

19. API Contracts Are Not Database Entities

Never expose persistence objects directly through public API.

Use dedicated DTOs.


20. packages/providers

Contains provider-specific implementations.

Recommended layout:

packages/providers/src/
├── common/
├── microsoft/
├── gmail/
└── icloud/

21. Provider Interface

Canonical interface may live in application or dedicated shared contracts.

Implementations:

MicrosoftGraphMailAdapter
GmailMailAdapter
ICloudMailAdapter

22. Microsoft Provider Module

Suggested contents:

microsoft/
├── graph-client.ts
├── auth.ts
├── message-mapper.ts
├── folder-mapper.ts
├── sync.ts
├── subscriptions.ts
├── commands.ts
└── adapter.ts

23. Gmail Provider Module

Suggested:

gmail/
├── gmail-client.ts
├── auth.ts
├── message-mapper.ts
├── label-mapper.ts
├── history-sync.ts
├── watch.ts
├── commands.ts
└── adapter.ts

24. iCloud Provider Module

Suggested:

icloud/
├── imap-client.ts
├── auth.ts
├── mime-mapper.ts
├── uid-sync.ts
├── folder-mapper.ts
└── adapter.ts

Initial iCloud implementation remains read-oriented.


25. Provider Mapping

All provider modules should translate external objects into canonical provider DTOs before application logic sees them.


26. Provider Capability Registry

Provider capabilities should be implemented centrally.

Example:

Microsoft:
read, search, archive, move, categories, drafts, send, push, delta

Gmail:
read, search, archive, labels, drafts, send, push/history

iCloud:
read, folders, incremental IMAP, limited write depending future decision

27. packages/security

Contains content-security components.

Suggested structure:

packages/security/src/
├── gateway/
├── html/
├── urls/
├── attachments/
├── quarantine/
├── policies/
└── findings/

28. Security Isolation

The package contains security logic, but untrusted heavy parsing may execute in isolated worker processes/containers.

The repository boundary and deployment boundary are separate concerns.


29. HTML Sanitization

Suggested module:

security/html/
├── sanitizer.ts
├── remote-content-policy.ts
├── link-rewriter.ts
└── safe-render-model.ts

30. URL Inspection

Suggested:

security/urls/
├── parser.ts
├── policy.ts
├── redirect-resolver.ts
├── reputation.ts
└── ssrf-guard.ts

31. Attachment Inspection

Suggested:

security/attachments/
├── metadata.ts
├── type-detector.ts
├── archive-inspector.ts
├── scanner-interface.ts
├── sandbox-interface.ts
└── policy.ts

32. packages/ai

AI behavior belongs behind model-independent interfaces.

Structure:

packages/ai/src/
├── gateway/
├── classification/
├── summarization/
├── drafting/
├── search-intent/
├── rule-suggestions/
├── schemas/
└── evaluations/

33. AI Gateway

Provider-specific model SDK usage should remain inside gateway implementations.

The rest of the application uses operations such as:

classifyMessage()
summarizeConversation()
generateDraft()
interpretSearch()

34. AI Output Schemas

Structured output schemas belong in a stable package and are reused by:

Runtime validation
Tests
Evaluation harness
API diagnostics

35. packages/persistence

Contains repository implementations and persistence mapping.

Example:

packages/persistence/src/
├── db/
├── repositories/
├── mappings/
├── transactions/
└── outbox/

36. Repository Interfaces vs Implementations

Interfaces belong with application/domain contracts.

Implementations belong in persistence.

Example:

MailRepository
→ interface

PostgresMailRepository
→ implementation

37. Database Schema

Database migration files should remain outside ORM-generated opaque state wherever practical.

Schema changes must be reviewable.


38. Database Naming

Suggested naming convention:

snake_case tables/columns
UUID primary keys
created_at
updated_at

Domain object naming can remain TypeScript-style.


39. Database Domains

Tables should group logically around:

accounts
mail
classification
rules
learning
security
commands
migration
audit
operations

but remain normalized rather than creating one schema/table per service without need.


40. JSON Policy

Use JSON only for:

Provider raw metadata
Flexible capability data
Structured AI trace metadata
Diagnostics
Non-core extensible payloads

Do not store the core relational model as JSON blobs.


41. packages/jobs

Contains durable job contracts and orchestration.

Example:

packages/jobs/src/
├── definitions/
├── handlers/
├── scheduling/
├── retries/
├── idempotency/
└── dead-letter/

42. Job Definitions

Jobs should be typed and versioned.

Example:

SyncMailboxJobV1
ClassifyMessageJobV1
ExecuteMailCommandJobV1
MigrateBatchJobV1

43. Job Handlers

Handlers should be thin:

Deserialize
Validate
Load application service
Execute
Record result

44. packages/observability

Shared instrumentation:

logging
metrics
tracing
correlation IDs
error classification

Provider/application code should use these abstractions rather than independent logging conventions.


45. packages/config

Contains:

Typed configuration schemas
Environment validation
Feature flags
Policy defaults
Runtime limit definitions

No secrets committed to repository.


46. packages/testing

Reusable test infrastructure:

Mock providers
Factories
Fixture loaders
Fake clocks
Fake queues
Domain builders
Assertions

47. Fake Clock

Time-dependent features such as:

Waiting
Due dates
Stale follow-up
Token expiration
Subscription renewal

should use injectable clock abstractions.

This avoids brittle tests.


48. Provider Mocks

Mock providers should satisfy the same contract as real providers where practical.


49. database/migrations

All production schema migrations live here and are version-controlled.


50. database/seeds

Only synthetic/reference data.

Never production email.


51. infrastructure

Contains infrastructure definitions and deployment configuration.

Suggested:

infrastructure/
├── environments/
│   ├── development/
│   └── production/
├── workers/
├── storage/
├── queues/
└── monitoring/

52. Infrastructure Is Separate From App Configuration

Do not place rules, mailbox roles, user preferences, or identities in infrastructure code.


53. tests/e2e

Contains product workflow tests.

Examples:

respond-to-waiting.spec.ts
system-alert.spec.ts
quarantine.spec.ts
identity-hygiene.spec.ts
rule-learning.spec.ts
migration.spec.ts

54. tests/security

Contains hostile/adversarial testing.

Example:

prompt-injection/
html/
urls/
attachments/
authorization/
secrets/

55. tests/provider-contracts

Common contract suite run against:

Mock Microsoft
Mock Gmail
Mock iCloud
Optional dedicated live development accounts

56. tests/ai-evals

Stores evaluation harness code and expected structured outcomes.

Sensitive user-derived evaluation data should not necessarily be committed unencrypted to source control.


57. fixtures/mail

Synthetic RFC-style messages.

Organize by:

human
financial
travel
system
commercial
security

58. fixtures/security

Examples:

malicious-html
tracking-pixel
phishing-links
ssrf-links
macro-documents
zip-bombs-safe-fixture
prompt-injection

Do not include real malware binaries in the normal repository.


59. Documentation Layout

Recommended:

docs/
├── requirements/
├── architecture/
├── decisions/
├── operations/
└── runbooks/

60. Requirements Directory

Holds authoritative product artifacts such as:

Functional Requirements
Security Specification
Migration Specification
Configuration Specification

61. Architecture Directory

Contains:

Technical Architecture
Processing Pipeline
Deployment Architecture
Canonical Data Model
API Contracts

62. Architecture Decision Records

docs/decisions should contain focused ADRs for decisions with meaningful alternatives.

Example:

ADR-001 PostgreSQL as Canonical Store
ADR-002 Microsoft Graph Instead of IMAP
ADR-003 Gmail API Instead of IMAP
ADR-004 Logical Message vs Message Instance
ADR-005 Provider Body as Source of Truth

63. Avoid Duplicate Documentation

An ADR should capture the decision and rationale.

It should not reproduce entire requirements documents.

Documentation should link rather than duplicate.


64. Operations Documentation

Examples:

Provider reconnect
OAuth scope change
Restore database
Run reconciliation
Pause automation
Recover dead-letter queue

65. Runbooks

Critical operational runbooks:

Provider auth expired
Graph subscription failed
Gmail watch expired
Security scanner unavailable
Unexpected mass action
Migration reconciliation failure
Suspected credential compromise

66. Dependency Direction

Recommended dependency direction:

UI
 ↓
API/Application
 ↓
Domain

Infrastructure Implementations
 ↑
Application Interfaces

The domain should sit at the center.


67. Forbidden Dependency Example

Prohibited:

domain/rules
imports
providers/gmail

Rules should know canonical fields, not Gmail.


68. Dependency Enforcement

Use lint/build rules where practical to enforce module boundaries.

Do not rely solely on developer discipline.


69. Import Aliases

Stable workspace aliases may include:

@inbox/domain
@inbox/application
@inbox/providers
@inbox/security
@inbox/ai
@inbox/persistence
@inbox/config
@inbox/testing

70. Naming Conventions

Use descriptive domain names.

Prefer:

MessageInstance
AttentionState
RuleExecution
SecurityFinding

over vague names such as:

Data
Item
Thing
Handler2

71. Command Naming

Application commands should use verbs:

ArchiveConversation
SetAttentionState
CreateDraft
ApproveRule
ReleaseQuarantine

72. Query Naming

Queries should describe retrieval:

GetNeedsMe
SearchMail
GetConversation
GetProviderHealth

73. Event Naming

Events use past tense:

MessageDiscovered
MessageQuarantined
CommandSucceeded
UserCorrectionRecorded

74. Provider Mapping Naming

Use explicit mapping names:

mapGraphMessageToProviderMessage()
mapGmailMessageToProviderMessage()

Do not leak raw SDK objects into application services.


75. Error Model

Shared application errors should have canonical codes.

Examples:

NOT_FOUND
POLICY_DENIED
APPROVAL_REQUIRED
PROVIDER_UNAVAILABLE
AUTH_EXPIRED
CONFLICT
RATE_LIMITED

Provider-specific exceptions should map into these.


76. No Raw Provider Errors to UI

External provider errors may contain implementation details or sensitive data.

Convert them before client exposure.


77. Transaction Boundaries

Database transactions should be owned in the application/persistence layer.

Domain objects should not start database transactions themselves.


78. Outbox Implementation

Outbox support belongs in persistence/jobs.

Application services write:

state change
+
outbox event

atomically.


79. Idempotency

Idempotency helpers should be reusable rather than reimplemented in every worker.


80. Correlation IDs

Correlation context should flow through:

API
Application service
Job
Provider adapter
Audit
Logs

81. Audit Integration

Do not scatter direct audit table writes throughout code.

Use a centralized audit interface.


82. Policy Gateway

All consequential mutations should route through one application-level policy gateway.

Avoid:

if approved:
   gmail.archive()

inside feature code.


83. Agent Tool Gateway

Agent tools should exist in a dedicated boundary.

Suggested:

application/agent-tools/
├── search-mail.ts
├── summarize.ts
├── request-archive.ts
├── request-draft.ts
├── explain.ts
└── propose-rule.ts

84. AI Cannot Import Provider Modules

The AI package must not directly import provider adapters for mutation.

Agent requests pass through application services.


85. Security Cannot Bypass Application Policy

Security services may quarantine/block according to security policy, but ordinary provider mutations still use appropriate command/service boundaries.


86. Rule Engine Package Location

Rule evaluation belongs primarily in domain/application.

Provider actions produced by rules become canonical action requests.


87. Rule DSL

Keep rule condition/action definitions as structured types.

Do not allow arbitrary JavaScript execution from stored rules.


88. Regex Safety

If regex is supported:

limit complexity
limit execution duration
validate patterns

89. Search Architecture

Search should have a dedicated application interface capable of combining:

PostgreSQL metadata
Provider-native content search
Future semantic index

Do not let UI call providers separately.


90. Future Semantic Search

If embeddings are later added, implement behind a search abstraction.

No core entity should require vector storage.


91. Future Native iOS Client

Repository may later add:

apps/ios/

or a separate native repository if mobile lifecycle justifies it.

The backend contract should not change merely because iOS is added.


92. Shared Generated Clients

api-contracts may generate:

TypeScript client
Swift client

from OpenAPI or equivalent machine-readable schemas.


93. Build Boundaries

Each package should expose intentional public entry points.

Avoid deep imports such as:

@inbox/domain/src/mail/internal/private-helper

94. Package Public APIs

Use package-level index exports to control dependencies.


95. Private Implementation

Internal helper modules should not automatically become cross-package dependencies.


96. Circular Dependency Prevention

The workspace should fail CI on problematic circular dependencies where tooling permits.


97. CI Pipeline

Recommended jobs:

install
typecheck
lint
unit-tests
contract-tests
security-tests
build
database-validation
preview-e2e

98. Changed-Package Optimization

CI may later run only affected packages for speed while retaining full regression runs before production as needed.


99. PR Discipline

Implementation should favor:

One coherent ticket/change
One branch
One PR

where feasible.

PRs should identify:

Requirement
Implementation
Tests
Risks
Schema changes

100. Source of Truth

Charter/Jira may drive implementation planning, but repository documentation remains authoritative for architecture and requirements.

Tickets should link to relevant sections rather than copy entire specifications.


101. README

Root README should remain concise.

Suggested contents:

Product summary
Architecture summary
Repo structure
Development setup
Common commands
Documentation links

Do not turn README into a duplicate architecture specification.


102. Developer Setup

Development bootstrap should ideally provide one command or short workflow to start:

Web
Local database
Mock queue
Mock providers
Synthetic fixtures

103. Mock-First Local Development

Default developer mode should use:

Mock Microsoft
Mock Gmail
Mock iCloud
Mock AI or deterministic AI fixtures

unless explicitly enabling development integrations.


104. Development Mail Viewer

A useful internal development tool may inspect synthetic messages and their processing history.

This should never require production data.


105. Schema Generation

If using ORM/schema tooling, generated code should be checked for reproducibility.

Database schema must remain understandable independently of generated client APIs.


106. Data Access Rules

Avoid arbitrary SQL inside UI or route handlers.

Data access should flow through repositories/application queries.


107. Performance Escape Hatch

Complex PostgreSQL queries may use carefully written SQL where appropriate.

Architecture should not force an ORM abstraction when direct SQL is materially better.


108. Migration Scripts

Historical mail migration scripts should not live as random one-off scripts.

Migration logic belongs in the Migration Service.

Operational scripts should invoke supported application interfaces.


109. scripts

Use only for controlled developer/admin utilities.

Examples:

validate-env
seed-fixtures
generate-api-client
run-evaluations
verify-migrations

110. No Dangerous Ad Hoc Scripts

Avoid scripts capable of mass deleting or moving production mail outside the command/policy/audit path.


111. Code Generation

Generated code should live in clearly marked locations.

Never manually edit generated files without documented process.


112. Formatting and Style

Use one shared formatting and lint configuration across TypeScript packages.


113. Strict TypeScript

Prefer strict TypeScript configuration.

Avoid widespread any.

Provider SDK boundaries may use unknown/raw types only until validated/mapped.


114. Runtime Validation

TypeScript types alone are insufficient for:

API requests
Provider responses
AI responses
Job payloads
Configuration

Validate untrusted runtime data.


115. Date/Time Handling

Use UTC internally for timestamps.

Convert to user timezone only at presentation or explicit scheduling boundaries.


116. Email Address Handling

Use dedicated normalization utilities.

Do not lowercase or transform fields blindly where RFC/provider semantics may matter.

Canonical comparison strategy should be defined centrally.


117. Hashing Utilities

Duplicate hashes, content fingerprints, and attachment hashes should use centralized implementations.


118. Testing Proximity

Unit tests should generally live near implementation.

Large cross-cutting suites remain in top-level tests.


119. Security Fixture Safety

Potentially dangerous fixture files should be inert/synthetic whenever possible.

Do not store active malware in source control merely for realism.


120. ADR Requirement

Create ADRs when implementation chooses among meaningful alternatives such as:

Queue technology
Database hosting
Authentication provider
AI provider
Object storage
HTML sanitizer
Security scanner

121. Implementation Decision vs Requirement

Do not rewrite a requirement simply because a library changes.

Example:

Requirement:
Durable background processing

Implementation:
Specific queue technology

Keep these separate.


122. Versioning

API, events, jobs, and database schema should each have explicit compatibility strategies.

They do not need to share one version number.


123. Application Version

Application release version may use:

major.minor.patch.build

or another agreed convention.


124. Changelog

Maintain a release changelog describing:

New capabilities
Changed behavior
Migration notes
Security changes
Breaking changes

Avoid listing every internal refactor.


125. Observability From Development

Logging/tracing interfaces should work locally with console/test implementations and production with managed implementations.


126. Repository Acceptance Criteria

This repository architecture is acceptable when: