207 lines
9.6 KiB
Markdown
207 lines
9.6 KiB
Markdown
# Implementation Plan: Config Wizard
|
|
|
|
## Overview
|
|
|
|
Implement `configure.js` as a single-file interactive CLI wizard at the project root. The implementation follows the design's module structure: constants/registry, parsing, validation, display/prompt, file writing, and main flow orchestration. Property-based tests use fast-check in `backend/__tests__/`.
|
|
|
|
## Tasks
|
|
|
|
- [x] 1. Set up project structure and install test dependencies
|
|
- [x] 1.1 Create `configure.js` with shebang, constants, and variable descriptor registry
|
|
- Add `#!/usr/bin/env node` header
|
|
- Define `VARIABLE_DESCRIPTORS` array with all 32 managed variables and their metadata (name, group, required, default, description, docUrl, sensitive, validator)
|
|
- Define `GROUP_ORDER` array, `GROUP_DESCRIPTIONS` object, and `SENSITIVE_VARS` list
|
|
- Export constants for testability using `module.exports` at the bottom (conditionally, so the file still runs as a script)
|
|
- _Requirements: 2.1, 2.2, 2.3, 2.4, 2.5, 3.1, 3.2, 3.3, 3.4_
|
|
|
|
- [x] 1.2 Install fast-check as a dev dependency in backend
|
|
- Run `npm install --save-dev fast-check` in `backend/`
|
|
- _Requirements: N/A (test infrastructure)_
|
|
|
|
- [x] 2. Implement parsing functions
|
|
- [x] 2.1 Implement `resolveShellDefault(str)` function
|
|
- Extract default value from `${VAR:-default}` pattern
|
|
- Return original string if pattern not found
|
|
- _Requirements: 4.1_
|
|
|
|
- [x] 2.2 Implement `parseDockerCompose(filePath)` function
|
|
- Line-by-line state machine parser for docker-compose.yml
|
|
- Extract POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DB, and host port
|
|
- Resolve shell variable substitution via `resolveShellDefault`
|
|
- Return `null` if file missing or unparseable
|
|
- _Requirements: 4.1, 4.2, 4.3, 4.4_
|
|
|
|
- [x] 2.3 Implement `parseEnvFile(filePath)` function
|
|
- Read file line by line, split on first `=`
|
|
- Separate managed variables from unmanaged lines (including preceding comments)
|
|
- Handle quoted values (strip surrounding double quotes)
|
|
- Return `{ managed: Map, unmanaged: String[] }`
|
|
- Return empty maps if file doesn't exist or is unreadable
|
|
- _Requirements: 9.1, 9.2, 9.4, 9.6_
|
|
|
|
- [ ]* 2.4 Write property test for shell default resolution
|
|
- **Property 5: Shell variable default resolution**
|
|
- **Validates: Requirements 4.1**
|
|
|
|
- [ ]* 2.5 Write property test for DATABASE_URL construction
|
|
- **Property 6: DATABASE_URL construction**
|
|
- **Validates: Requirements 4.2**
|
|
|
|
- [ ]* 2.6 Write property test for env file round-trip parsing
|
|
- **Property 16: Env file round-trip parsing**
|
|
- **Validates: Requirements 9.1, 9.2**
|
|
|
|
- [x] 3. Implement validation functions
|
|
- [x] 3.1 Implement all validation functions
|
|
- `validatePort(value)` — integer in [1, 65535]
|
|
- `validateCorsOrigins(value)` — each comma-separated entry starts with http:// or https://
|
|
- `validateDatabaseUrl(value)` — starts with `postgresql://` or equals `sqlite`
|
|
- `validateSessionSecret(value)` — at least 16 characters
|
|
- `validateRequired(value)` — non-empty, non-whitespace-only
|
|
- _Requirements: 5.1, 5.2, 5.3, 5.4, 5.6_
|
|
|
|
- [ ]* 3.2 Write property tests for validation functions
|
|
- **Property 8: Port validation**
|
|
- **Property 9: CORS origins validation**
|
|
- **Property 10: DATABASE_URL validation**
|
|
- **Property 11: SESSION_SECRET validation**
|
|
- **Property 12: Required variable rejection of whitespace**
|
|
- **Validates: Requirements 5.1, 5.2, 5.3, 5.4, 5.6**
|
|
|
|
- [x] 4. Implement display and prompt functions
|
|
- [x] 4.1 Implement display functions
|
|
- `printWelcome()` — purpose and instructions
|
|
- `printGroupHeader(group)` — group name and description
|
|
- `printSummary(config, skippedGroups)` — table with masked sensitive values, target file paths, overwrite indicators
|
|
- `maskSensitive(name, value)` — first 4 + last 4 with asterisks for strings > 8 chars, full value otherwise
|
|
- _Requirements: 1.2, 2.3, 3.4, 8.1, 8.2, 8.3_
|
|
|
|
- [x] 4.2 Implement prompt functions
|
|
- `promptVariable(rl, descriptor, currentValue)` — display label, description, default/current, docUrl; validate input; re-prompt on failure
|
|
- `promptYesNo(rl, question, defaultNo)` — yes/no with configurable default
|
|
- `promptOverwrite(rl, filePath)` — confirm overwrite, offer backup
|
|
- _Requirements: 3.1, 3.2, 3.3, 3.5, 5.5, 6.5, 7.1, 9.3_
|
|
|
|
- [ ]* 4.3 Write property test for sensitive value masking
|
|
- **Property 4: Sensitive value masking**
|
|
- **Validates: Requirements 3.4**
|
|
|
|
- [ ]* 4.4 Write property test for derived URL defaults from PORT
|
|
- **Property 7: Derived URL defaults from PORT**
|
|
- **Validates: Requirements 4.6**
|
|
|
|
- [x] 5. Checkpoint
|
|
- Ensure all tests pass, ask the user if questions arise.
|
|
|
|
- [x] 6. Implement file writing functions
|
|
- [x] 6.1 Implement `generateEnvContent(variables, groupOrder, groupDescriptions, unmanagedLines)` function
|
|
- Group header comments (`# --- Group Name ---`)
|
|
- `KEY=value` lines with conditional double-quote wrapping (spaces, `#`, quotes)
|
|
- Omit optional variables with no value and no default
|
|
- Append unmanaged variables in `# --- Custom Variables ---` section
|
|
- _Requirements: 6.1, 6.2, 6.3, 6.4, 9.4, 9.5_
|
|
|
|
- [x] 6.2 Implement `writeEnvFile(filePath, content)` and `createBackup(filePath)` functions
|
|
- Write content to file path using `fs.writeFileSync`
|
|
- `createBackup` copies existing file to `{filename}.backup.{YYYYMMDD_HHmmss}`
|
|
- Handle filesystem errors with descriptive messages
|
|
- _Requirements: 6.5, 6.6_
|
|
|
|
- [ ]* 6.3 Write property test for env value quoting
|
|
- **Property 13: Env value quoting**
|
|
- **Validates: Requirements 6.3**
|
|
|
|
- [ ]* 6.4 Write property test for optional variable omission
|
|
- **Property 14: Optional variable omission**
|
|
- **Validates: Requirements 6.4**
|
|
|
|
- [ ]* 6.5 Write property test for skipped group exclusion
|
|
- **Property 15: Skipped group exclusion**
|
|
- **Validates: Requirements 7.2, 7.3**
|
|
|
|
- [ ]* 6.6 Write property test for unmanaged variable preservation
|
|
- **Property 17: Unmanaged variable preservation**
|
|
- **Validates: Requirements 9.4**
|
|
|
|
- [ ]* 6.7 Write property test for managed key deduplication
|
|
- **Property 18: Managed key deduplication**
|
|
- **Validates: Requirements 9.5**
|
|
|
|
- [x] 7. Implement main flow orchestration
|
|
- [x] 7.1 Implement `main()` function and wire all components together
|
|
- Validate project root (check `backend/` and `frontend/` exist)
|
|
- Parse existing env files for pre-fill defaults
|
|
- Parse docker-compose.yml for derived defaults
|
|
- Set up readline interface and SIGINT handler
|
|
- Group loop: iterate GROUP_ORDER, prompt skip for optional groups, prompt each variable
|
|
- Derive REACT_APP_API_BASE, REACT_APP_API_HOST, CORS_ORIGINS from confirmed PORT
|
|
- Display summary, prompt confirmation (approve / restart / exit)
|
|
- Handle overwrite prompts and write both env files
|
|
- Display success message with next steps
|
|
- Exit code 0 on success, 1 on error/cancel
|
|
- _Requirements: 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 4.5, 4.6, 7.1, 7.2, 7.3, 7.4, 8.1, 8.2, 8.3, 8.4, 8.5_
|
|
|
|
- [x] 8. Checkpoint
|
|
- Ensure all tests pass, ask the user if questions arise.
|
|
|
|
- [ ] 9. Write descriptor registry property tests
|
|
- [ ]* 9.1 Write property test for descriptor registry invariants
|
|
- **Property 1: Descriptor registry invariants**
|
|
- **Validates: Requirements 2.3, 2.5**
|
|
|
|
- [ ]* 9.2 Write property test for variable ordering within groups
|
|
- **Property 2: Variable ordering within groups**
|
|
- **Validates: Requirements 2.4**
|
|
|
|
- [ ]* 9.3 Write property test for group presentation order
|
|
- **Property 3: Group presentation order**
|
|
- **Validates: Requirements 2.1**
|
|
|
|
- [ ] 10. Write integration and unit tests
|
|
- [ ]* 10.1 Write unit tests for parseDockerCompose
|
|
- Test valid compose files, missing files, malformed content
|
|
- _Requirements: 4.1, 4.2, 4.3, 4.4_
|
|
|
|
- [ ]* 10.2 Write unit tests for parseEnvFile
|
|
- Test standard files, quoted values, comments, empty lines, malformed lines
|
|
- _Requirements: 9.1, 9.2, 9.4, 9.6_
|
|
|
|
- [ ]* 10.3 Write unit tests for generateEnvContent
|
|
- Test group headers, quoting rules, omission of empty optionals, custom variables section
|
|
- _Requirements: 6.1, 6.2, 6.3, 6.4, 9.4, 9.5_
|
|
|
|
- [ ]* 10.4 Write integration tests for full wizard flow
|
|
- Test full run with defaults accepted, existing env pre-fill, skipped groups, SIGINT handling, missing project structure error
|
|
- Use temporary directories and mock readline input
|
|
- _Requirements: 1.1, 1.4, 1.5, 7.1, 7.2, 7.3, 8.4, 8.5, 9.1_
|
|
|
|
- [x] 11. Final checkpoint
|
|
- Ensure all tests pass, ask the user if questions arise.
|
|
|
|
## Notes
|
|
|
|
- Tasks marked with `*` are optional and can be skipped for faster MVP
|
|
- Each task references specific requirements for traceability
|
|
- Checkpoints ensure incremental validation
|
|
- Property tests validate universal correctness properties from the design document
|
|
- Unit tests validate specific examples and edge cases
|
|
- All code goes in a single `configure.js` file at the project root
|
|
- Tests go in `backend/__tests__/` using Jest + fast-check
|
|
- The file uses `module.exports` conditionally (only when `require.main !== module`) so it can be both a runnable script and importable for testing
|
|
|
|
## Task Dependency Graph
|
|
|
|
```json
|
|
{
|
|
"waves": [
|
|
{ "id": 0, "tasks": ["1.1", "1.2"] },
|
|
{ "id": 1, "tasks": ["2.1", "2.2", "2.3", "3.1"] },
|
|
{ "id": 2, "tasks": ["2.4", "2.5", "2.6", "3.2", "4.1", "4.2"] },
|
|
{ "id": 3, "tasks": ["4.3", "4.4", "6.1", "6.2"] },
|
|
{ "id": 4, "tasks": ["6.3", "6.4", "6.5", "6.6", "6.7", "7.1"] },
|
|
{ "id": 5, "tasks": ["9.1", "9.2", "9.3", "10.1", "10.2", "10.3"] },
|
|
{ "id": 6, "tasks": ["10.4"] }
|
|
]
|
|
}
|
|
```
|