Files
google-drive-content-adapter/.specify/memory/constitution.md
Peter.Morton f6710203c7 Reorganize project structure: relocate proxy.js and global directory
- Move src/proxy.js → src/proxyScripts/proxy.js
- Move global/ → src/globalVariables/
- Update constitution.md to reflect new file locations
- Update all documentation references to new paths
- Consolidate all source code under src/ directory

Constitution version: 1.15.0 → 1.16.0

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-07 10:35:03 -06:00

502 lines
25 KiB
Markdown

<!--
Sync Impact Report:
Version: 1.15.0 → 1.16.0 (PATCH: Directory relocation and documentation update)
Modified Principles:
- Section I: Updated all references to global/ directory to src/globalVariables/
- Section I.II: Updated file structure to reflect global/ → src/globalVariables/
- Section I.IV: Updated configuration section to reference src/globalVariables/
- Section I.V: Updated global objects documentation to reference src/globalVariables/
Documentation Changes:
- Updated all references to global/ directory to src/globalVariables/
- Clarified that src/globalVariables/ contains JSON data files loaded at startup
- Updated file structure documentation to show correct hierarchy
Code Changes:
- Relocated: global/ → src/globalVariables/
- No logic changes to any files
Modified Sections:
- Section I: Multiple references to global directory location
- Section I.II: File structure documentation
- Section I.IV: Configuration section
- Section I.V: Global objects injection section
Templates Status:
✅ All templates - No changes needed (directory relocation only)
Follow-up TODOs:
- Update server.js to load global objects from new location (src/globalVariables/)
Previous Version:
Version: 1.14.0 → 1.15.0 (PATCH: File relocation and documentation update)
Modified Principles:
- Section I.II: Updated file structure to reflect proxy.js relocation to src/proxyScripts/
- Section I.III: Updated enforcement rules to reflect new proxy.js location
Documentation Changes:
- Updated all references to proxy.js to reflect new location at src/proxyScripts/proxy.js
- Clarified that src/proxyScripts/ contains the main proxy script (singular, not plural scripts)
- Updated file structure documentation to show correct hierarchy
Code Changes:
- Relocated: src/proxy.js → src/proxyScripts/proxy.js
- Created directory: src/proxyScripts/
- No logic changes to proxy.js itself
Modified Sections:
- Section I.II: File structure documentation
- Section I.III: Enforcement rules
- All references to proxy.js location throughout document
Templates Status:
✅ All templates - No changes needed (file relocation only)
Follow-up TODOs:
- Update server.js to load proxy.js from new location (src/proxyScripts/proxy.js)
Previous Version:
Version: 1.13.0 → 1.14.0 (PATCH: Documentation corrections to match actual implementation)
Modified Principles:
- Section I.V: Removed config from context injection (proxy.js doesn't need infrastructure settings)
- Section I.V: Documented spread operator pattern (globalVMContext and globalVariableContext)
- Section I.V: Clarified direct variable access pattern for proxy.js
- Section I.V: Updated injection pattern to show actual loadGlobalObjects() → globalVariableContext flow
- Section I.V: Renumbered items after removing config (was 12 items, now 11)
- Section I.V: Enhanced rationale to explain spread operator benefits
Documentation Changes:
- Removed config: global.config from context injection example (not actually injected)
- Added explicit code example showing globalVMContext and globalVariableContext definitions
- Clarified that proxy.js uses direct variable access: `const x = google_drive_settings;`
- Documented spread operator pattern: `{ ...globalVMContext, ...globalVariableContext, req, res }`
- Added note about URL availability (not in globalVMContext but available via Node.js)
No Code Changes:
- This is purely a documentation update to match existing implementation
- No JavaScript files modified
- Constitution now accurately reflects server.js and proxy.js patterns
Modified Sections:
- Section I.V: Complete rewrite of VM Context Injection Pattern section
- Section I.V: Rationale updated to explain spread operator benefits
Templates Status:
✅ All templates - No changes needed (documentation-only update)
Follow-up TODOs:
- Consider updating proxy.js to use direct variable access instead of globalThis["name"]
-->
# Proxy Scripts Constitution
## Core Principles
### I. Monolithic Architecture (NON-NEGOTIABLE)
**ALL business logic, data processing, authentication, and request handling MUST exist within the `src/proxyScripts/proxy.js` file.** The `server.js` file should ONLY handle:
- HTTP server setup
- Configuration loading
- Global object injection into isolated context
- Loading src/proxyScripts/proxy.js via `vm.Script` and `vm.createContext`
- Per-request context creation with all necessary globals
**Implementation via vm.Script**:
`src/proxyScripts/proxy.js` MUST be loaded using Node.js `vm.Script` and executed in isolated contexts created per-request with `vm.createContext`. This ensures:
- Complete isolation from server.js module system
- All dependencies provided explicitly through context objects
- Zero ability to import/export modules
- Pure functional execution with injected dependencies
**Rationale**: Monolithic architecture enables simple packaging as a single IVA Studio proxy script and prevents fragmentation of business logic across multiple files. Using `vm.Script` enforces architectural boundaries at runtime, making it impossible for `src/proxyScripts/proxy.js` to access Node.js module system or file system, ensuring ALL functionality exists in one isolated, dependency-injected file.
### I. Zero External Imports or Exports from `src/proxyScripts/proxy.js` (NON-NEGOTIABLE)
`src/proxyScripts/proxy.js` MUST have **ZERO import statements**. All dependencies MUST be provided through `vm.createContext` by server.js.
`src/proxyScripts/proxy.js` MUST have **ZERO export statements**. The file MUST be pure JavaScript code executed in an isolated VM context.
**File system access** from `src/proxyScripts/proxy.js` is **ABSOLUTELY PROHIBITED** under any circumstances. The `fs` module MUST NOT be accessible.
**External libraries** (axios, jwt, googleapis, etc.) MUST NOT be imported. Dependencies are injected through VM context by server.js.
**Rationale**: Using `vm.Script` and `vm.createContext` enforces architectural boundaries at the VM level. src/proxyScripts/proxy.js runs in an isolated context with NO access to Node.js module system, file system, or process globals. ALL dependencies must be explicitly injected per-request through the context object, ensuring src/proxyScripts/proxy.js contains ONLY pure business logic with zero capability for I/O operations.
**For data files that src/proxyScripts/proxy.js needs** (service account keys, certificates, secrets):
1. Place JSON files in `src/globalVariables/` directory
2. server.js loads them at startup using `loadGlobalObjects()`
3. server.js injects them into VM context per-request via `vm.createContext`
4. src/proxyScripts/proxy.js accesses them as simple variables in context (e.g., `google_drive_settings`)
**Example**:
- File: `src/globalVariables/google_drive_settings.json`
- Loading: server.js reads and assigns to `globalVariableContext.google_drive_settings`
- Injection: server.js adds `google_drive_settings: globalVariableContext.google_drive_settings` to context
- Access in src/proxyScripts/proxy.js: Direct variable access `google_drive_settings.serviceAccount`
**Enforcement**:
- src/proxyScripts/proxy.js MUST have NO `import` statements (file should start with comments, then code)
- src/proxyScripts/proxy.js MUST have NO `export` statements (no module.exports, no export keyword)
- Any `import` or `export` in src/proxyScripts/proxy.js MUST be rejected immediately
- server.js MUST load src/proxyScripts/proxy.js using `vm.Script` constructor
- server.js MUST execute via `script.runInContext(context)` with fresh context per request
- All dependencies injected through `vm.createContext({ ... })` context object
- VM isolation prevents access to require(), import(), fs, process, and Node.js globals
#### I.I What MUST Be in src/proxyScripts/proxy.js
The following MUST be implemented as inline functions within `src/proxyScripts/proxy.js`:
1. **Authentication**: Service Account JWT, OAuth flows, token management
2. **Business Logic**: All request handling, routing, and processing
3. **Data Transformation**: Document parsing, XML generation, data mapping
4. **API Integration**: Drive API queries, error mapping, response handling
5. **Request Queue**: FIFO queue for sequential processing
6. **Utility Functions**: Request ID generation, validation, XML escaping, date formatting
7. **Error Handling**: All error mapping and HTTP status code logic
**NO EXCEPTIONS** - Even complex authentication (OAuth 2.0, JWT) must be inline.
#### I.II What Can Be Separate Files
ONLY the following infrastructure modules may exist outside `src/proxyScripts/proxy.js`:
1. **src/logger.js**: Structured logging with console replacement (ONLY logging, no business logic)
2. **src/server.js**: HTTP server bootstrap and configuration (ONLY server setup, no business logic)
3. **config/**: JSON configuration files (data files, not code)
4. **src/globalVariables/**: JSON data files loaded at startup (credentials, settings)
5. **src/proxyScripts/**: Directory containing the main proxy script (proxy.js)
**Test files are exempt** - Test utilities may exist solely for test compatibility if needed, but MUST NOT be imported by production code.
**File Structure**:
```
src/
├── proxyScripts/
│ └── proxy.js # Main business logic (monolithic)
├── globalVariables/
│ └── *.json # Data files for VM context
├── logger.js # Structured logging
└── server.js # HTTP server bootstrap
config/
└── default.json # Infrastructure settings
```
#### I.III Enforcement
During code review and planning:
- ANY file in `src/proxyScripts/` besides `proxy.js` MUST be challenged
- ANY file in `src/` besides `proxyScripts/`, `logger.js`, `server.js` MUST be challenged
- Authentication, even if complex, MUST be inline in `src/proxyScripts/proxy.js`
- Exceptions require explicit constitutional justification with measurable trade-offs
- When in doubt, inline it in `src/proxyScripts/proxy.js`
**RED FLAGS to reject immediately:**
- Separate files for: auth, database, utilities, helpers, services, controllers, models
- Any file containing business logic or domain knowledge
- Multiple files "organizing" the codebase
#### I.IV Configuration
- Configuration for the Node.js web server infrastructure should be stored as JSON in `config/default.json`.
- `config/default.json` MUST contain ONLY infrastructure settings: server (host, port), logging level
- `config/default.json` MUST NOT contain authentication credentials, secrets, API keys, or behavioral configuration
- Authentication credentials, secrets, and ALL behavioral configuration MUST be stored in `src/globalVariables/` directory as JSON files
- Global JSON files are automatically loaded by server.js and made available as global objects
- server.js should validate both configuration from `config/default.json` AND global objects from `src/globalVariables/` directory
#### I.V Global Objects Provided by server.js
The `server.js` file MUST inject the following objects into VM context for use by `src/proxyScripts/proxy.js`:
**VM Context Injection Pattern:**
server.js uses a spread operator pattern for cleaner context creation:
```javascript
// Define static VM context (libraries and built-ins)
const globalVMContext = {
URLSearchParams,
console: logger,
crypto,
axios,
uuidv4,
jwt,
xmlBuilder,
};
// Load dynamic data from src/globalVariables/ directory into globalVariableContext
let globalVariableContext = {}; // Populated by loadGlobalObjects()
// Per-request: Create fresh context with all dependencies
const context = vm.createContext({
...globalVMContext, // Spread static dependencies
...globalVariableContext, // Spread dynamic data (e.g., google_drive_settings)
req, // Fresh request object
res // Fresh response object
});
script.runInContext(context);
```
**Note:** src/proxyScripts/proxy.js accesses these as direct variables (e.g., `google_drive_settings`, not `globalThis["google_drive_settings"]`). The VM context makes all properties available as top-level variables.
**Core Infrastructure Context Variables:**
1. **console** - Custom logger from `logger.js`
- Purpose: Structured JSON logging
- Usage: `console.info()`, `console.debug()`, `console.error()`
- Injected from: `globalVMContext.console` (set to `logger`)
2. **crypto** - Web Crypto API (built-in)
- Purpose: UUID generation, cryptographic operations
- Usage: `crypto.randomUUID()`, etc.
- Injected from: `globalVMContext.crypto`
- Note: Web Crypto API available by default in Node.js
3. **axios** - HTTP client library
- Purpose: Making HTTP requests to external APIs
- Usage: `axios.get(url)`, `axios.post(url, data)`
- Package: `axios`
- Injected from: `globalVMContext.axios`
4. **uuidv4** - UUID v4 generator
- Purpose: Generate RFC4122 compliant UUIDs
- Usage: `uuidv4()` returns string like "110ec58a-a0f2-4ac4-8393-c866d813b8d1"
- Package: `uuid` (v4 function only)
- Injected from: `globalVMContext.uuidv4`
5. **jwt** - JSON Web Token library
- Purpose: Creating and verifying JWTs for authentication
- Usage: `jwt.sign(payload, secret)`, `jwt.verify(token, secret)`
- Package: `jsonwebtoken`
- Injected from: `globalVMContext.jwt`
6. **xmlBuilder** - XML builder/generator
- Purpose: Constructing XML documents programmatically
- Usage: `xmlBuilder({ root: { child: 'value' } })`
- Package: `xmlbuilder2` (create function)
- Injected from: `globalVMContext.xmlBuilder`
**Built-in Web APIs:**
7. **URLSearchParams** - URL query string parser (built-in)
- Purpose: Parse and manipulate URL query strings
- Usage: `new URLSearchParams(queryString)`
- Injected from: `globalVMContext.URLSearchParams`
8. **URL** - URL parser (built-in)
- Purpose: Parse and manipulate URLs
- Usage: `new URL(urlString)`
- Injected from: `globalVMContext.URL`
- Note: Currently not included in globalVMContext but available in Node.js by default
**Dynamic Data Context Variables:**
9. **Dynamic JSON objects from src/globalVariables/ directory**
- Purpose: Authentication credentials, secrets, API keys, and behavioral configuration
- Pattern: Each `src/globalVariables/filename.json` loaded by server.js → added to `globalVariableContext` → spread into VM context
- Examples:
- `src/globalVariables/google_drive_settings.json` → context variable `google_drive_settings` (consolidated service account, scopes, drive query, sitemap config)
- `src/globalVariables/api-keys.json` → context variable `api_keys` (API keys and secrets)
- `src/globalVariables/custom-config.json` → context variable `custom_config` (behavioral settings)
- Usage in src/proxyScripts/proxy.js: Direct variable access `const settings = google_drive_settings;`
- Loading: By server.js at startup using `loadGlobalObjects()` function
- Injection: Via spread operator `...globalVariableContext` in `vm.createContext()`
- **Note**: ALL authentication, secrets, and behavioral configuration MUST be in src/globalVariables/, NEVER in config/default.json
**Request/Response Objects:**
10. **req** - HTTP IncomingMessage
- Purpose: Access request data (URL, method, headers, body)
- Injected fresh: Per-request from `http.createServer((req, res) => ...)`
11. **res** - HTTP ServerResponse
- Purpose: Send response to client
- Injected fresh: Per-request from `http.createServer((req, res) => ...)`
**Rationale**: Using `vm.createContext` with spread operator pattern for dependency injection achieves:
- **Runtime-enforced isolation** - src/proxyScripts/proxy.js physically cannot access Node.js module system or file system
- **Zero imports possible** - VM context has no `require()` or `import()` capability
- **Explicit dependencies** - All available objects must be explicitly listed in globalVMContext or globalVariableContext
- **Clean organization** - Static dependencies (globalVMContext) separated from dynamic data (globalVariableContext)
- **Per-request isolation** - Fresh context per request prevents cross-request state leakage
- **Testing simplicity** - Mock entire context object instead of individual module imports
- **Clear contracts** - Context spread pattern documents every dependency src/proxyScripts/proxy.js uses
- **Security boundaries** - VM sandbox prevents escape to underlying system
- **DRY principle** - Spread operators eliminate repetitive property declarations
#### I.VI Logging
Modify server.js to replace the global `console` object with the `logger` export from `logger.js`. This will make all console.log, console.info, console.error calls throughout the application use the custom logger.
Logging should use `logger.js` module that has the following functions:
- log - which defaults to the 'info' function
- info - which writes to stdout
- debug - which prefixes the output with "[DEBUG]" written in red font and writes to stdout
- error - which prefixes the output with "[ERROR]" written in red font and writes to stderr
### II. API-First Design
Every feature MUST expose a clear, documented API before implementation begins. APIs MUST follow RESTful principles where applicable, use consistent naming conventions, and include comprehensive error handling with meaningful status codes and messages.
**Rationale**: API-first design ensures contracts are stable, enables parallel front-end/back-end work, facilitates integration testing, and produces naturally documented systems.
### III. Test-First Development (NON-NEGOTIABLE)
Test-Driven Development is MANDATORY for all production code. The cycle MUST be:
1. Write failing tests
2. Obtain user approval of test scenarios
3. Implement minimum code to pass tests
4. Refactor while maintaining green tests
Unit tests MUST achieve minimum 80% code coverage. Integration tests MUST cover all API contracts and critical user flows.
**Rationale**: TDD catches defects early, documents expected behavior, enables confident refactoring, and ensures all code paths are exercised.
### IV. Security & Privacy by Default
All user data MUST be treated as sensitive. OAuth tokens, credentials, and personal information MUST be encrypted at rest and in transit. The principle of least privilege MUST govern all access controls. Audit logging MUST track all data access and modifications.
**Rationale**: Privacy violations damage trust and carry legal liability. Security must be foundational, not retrofitted.
### V. Observability & Debuggability
All operations MUST emit structured logs with appropriate severity levels (DEBUG, INFO, WARN, ERROR). Errors MUST include context (request IDs, user IDs, operation names) sufficient for diagnosis. Performance-critical paths MUST expose metrics (latency, throughput, error rates).
**Rationale**: Production issues are inevitable. Observable systems reduce mean time to resolution and enable proactive problem detection.
### VI. Semantic Versioning & Change Management
All public APIs MUST follow semantic versioning (MAJOR.MINOR.PATCH):
- MAJOR: Breaking changes that require consumer updates
- MINOR: Backward-compatible feature additions
- PATCH: Backward-compatible bug fixes
Breaking changes MUST include migration guides and deprecation notices for at least one MINOR version before removal.
**Rationale**: Clear versioning communicates impact, enables safe upgrades, and respects downstream consumers' need for stability.
### VII. Simplicity, Minimal Dependencies & YAGNI
Implement only features with demonstrated need. Choose the simplest solution that satisfies current requirements. Reject premature optimization and speculative features. Complexity MUST be explicitly justified with measurable benefits.
**Dependency Minimization**: Prefer Node.js built-in modules over external npm packages. Each external dependency MUST be justified by:
- Significant functionality that would take >2 days to implement correctly
- Active maintenance and security track record
- Clear, documented benefit that outweighs maintenance risk
Prohibited without explicit approval:
- Utility libraries for functionality Node.js provides natively (fs, path, crypto, http, etc.)
- Heavy framework dependencies when lightweight alternatives exist
- Multiple packages solving the same problem
**Rationale**: External dependencies introduce supply chain risk, increase bundle size, complicate auditing, and create maintenance burden. Node.js built-ins are stable, well-tested, and maintained by the platform.
## API Design Standards
All external APIs MUST:
- Accept and return JSON for structured data
- Use standard HTTP methods (GET, POST, PUT, DELETE, PATCH) semantically
- Return appropriate HTTP status codes (2xx success, 4xx client errors, 5xx server errors)
- Include rate limiting headers where applicable
- Version endpoints explicitly (e.g., /v1/, /v2/)
- Document all parameters, responses, and error codes using OpenAPI/Swagger
Response formats MUST be consistent and include:
- Timestamp of response generation
- Request correlation ID for tracing
- Pagination metadata for list operations
- Clear error messages with actionable guidance
## Security & Data Protection
Authentication & Authorization MUST:
- Never log or expose credentials, tokens, or API keys
- Validate all input to prevent injection attacks
- Apply rate limiting to prevent abuse
Data Handling MUST:
- Minimize data retention—delete temporary files promptly
- Encrypt sensitive data using industry-standard algorithms (AES-256 or equivalent)
- Sanitize all user-supplied content before processing
- Implement CSRF protection for web interfaces
## Development Workflow
Code Reviews MUST:
- Verify alignment with all constitutional principles
- Check test coverage meets minimum thresholds
- Validate API contracts match documentation
- Confirm security best practices are followed
Quality Gates (ALL must pass before merge):
- All tests pass (unit, integration, end-to-end)
- Code coverage ≥ 80%
- No critical security vulnerabilities (use automated scanning)
- Documentation updated for API/behavior changes
- Performance regression checks pass
Deployment MUST:
- Use automated CI/CD pipelines
- Include smoke tests post-deployment
- Support rollback within 5 minutes
- Include release notes documenting all changes
## Technology Stack
**Platform**: Node.js (LTS version or later)
**Mandatory Baseline**:
- Use Node.js built-in modules as first choice (fs, path, crypto, http, https, stream, util, url, querystring, etc.)
- **DO NOT use 'events' EventEmitter** - implement simple patterns directly (e.g., Promise-based queues)
- Plain JavaScript (ES2022+) without TypeScript
- JSDoc comments for type documentation where needed
- JavaScript tooling (ESLint, Prettier) does not count against dependency budget
- Native test runner (node:test) or minimal test framework
**Dependency Approval Process**:
Any external npm package (excluding JavaScript tooling like ESLint and Prettier) MUST be justified in the feature specification with:
1. **Functionality gap**: What Node.js built-ins cannot do
2. **Implementation cost**: Estimated effort to build vs. maintain dependency
3. **Risk assessment**: Package security, maintenance history, download stats
4. **Alternatives considered**: Why alternatives were rejected
**Examples of acceptable dependencies** (when justified):
- xmlbuilder2
- axios
- uuid
**Examples of prohibited dependencies** (use Node.js built-ins or inline implementations instead):
- lodash/underscore (use native Array/Object methods)
- moment/date-fns (use native Date, Intl.DateTimeFormat)
- rimraf (use fs.rm with recursive: true)
- mkdirp (use fs.mkdir with recursive: true)
- **EventEmitter from 'events'** (implement simple queue classes directly - no need for event system)
- express/fastify (use native http/https for simple servers
**Node.js built-in modules to prefer:**
- Use 'node:' prefix for clarity: `import crypto from 'node:crypto'`
- Acceptable built-ins: fs, path, crypto, http, https, stream, util, url, querystring, etc.
- NOT acceptable: 'events' EventEmitter - implement patterns directly without event system
IMPORTANT : All dependencies that are not acceptable must be approved when running plan and task agents
## Governance
This constitution supersedes all other development practices and guidelines. When conflicts arise between this document and team conventions, the constitution takes precedence.
Amendments to this constitution require:
1. Documented justification explaining the need for change
2. Impact analysis of affected systems and workflows
3. Approval from project maintainers
4. Migration plan for any breaking changes
5. Update of version number following semantic versioning rules
All pull requests, code reviews, and design discussions MUST verify compliance with constitutional principles. Exceptions MUST be rare, explicitly justified with measurable trade-offs, and documented in the relevant specification or plan.
For runtime development guidance, refer to `.github/prompts/` and `.github/agents/` files which operationalize these principles into agent workflows.
**Version**: 1.14.0 | **Ratified**: 2026-03-05 | **Last Amended**: 2026-03-07