@friggframework/devtools 2.0.0--canary.666.81647c4.0 → 2.0.0--canary.668.8e53aa9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/frigg-cli/README.md +1 -38
- package/frigg-cli/__tests__/unit/commands/build.test.js +0 -3
- package/frigg-cli/__tests__/unit/commands/deploy.test.js +0 -3
- package/frigg-cli/build-command/index.js +0 -6
- package/frigg-cli/deploy-command/index.js +0 -6
- package/frigg-cli/index.js +1 -13
- package/frigg-cli/init-command/backend-first-handler.js +46 -25
- package/frigg-cli/start-command/index.js +0 -4
- package/frigg-cli/start-command/start-command.test.js +0 -3
- package/infrastructure/create-frigg-infrastructure.js +1 -4
- package/infrastructure/docs/POSTGRES-CONFIGURATION.md +98 -60
- package/package.json +7 -7
- package/frigg-cli/__tests__/unit/commands/validate-wiring.test.js +0 -92
- package/frigg-cli/validate-command/__tests__/init-validation.test.js +0 -63
- package/frigg-cli/validate-command/__tests__/integrations-checks.test.js +0 -133
- package/frigg-cli/validate-command/__tests__/validate-app-definition.test.js +0 -326
- package/frigg-cli/validate-command/__tests__/validate-command.test.js +0 -241
- package/frigg-cli/validate-command/checks/config.js +0 -468
- package/frigg-cli/validate-command/checks/integrations.js +0 -274
- package/frigg-cli/validate-command/format-report.js +0 -58
- package/frigg-cli/validate-command/index.js +0 -107
- package/frigg-cli/validate-command/load-app-definition.js +0 -93
- package/frigg-cli/validate-command/schema-issues.js +0 -154
- package/frigg-cli/validate-command/validate-app-definition.js +0 -60
- package/infrastructure/app-definition-schema-contract.test.js +0 -607
- package/infrastructure/create-frigg-infrastructure.test.js +0 -51
package/frigg-cli/README.md
CHANGED
|
@@ -110,41 +110,6 @@ Found 5 modules matching "crm"
|
|
|
110
110
|
|
|
111
111
|
---
|
|
112
112
|
|
|
113
|
-
#### `frigg validate [options]`
|
|
114
|
-
|
|
115
|
-
Validate the app definition (`index.js`) before you build or deploy it (ADR-051).
|
|
116
|
-
|
|
117
|
-
**Usage:**
|
|
118
|
-
```bash
|
|
119
|
-
frigg validate # schema + runtime checks
|
|
120
|
-
frigg validate --stage prod # also the stage checks (encryption, deploy-time environment)
|
|
121
|
-
frigg validate --json # machine-readable report for CI
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
**What it does:**
|
|
125
|
-
1. Loads `index.js` the way `frigg build` does (current directory, or the nearest `backend/`)
|
|
126
|
-
2. Validates it against the app-definition schema: unknown keys (with "did you mean"), types, and the values the infrastructure builders accept
|
|
127
|
-
3. Checks what the schema cannot: integration classes (static `Definition` with a valid, unique `name`, `version`, `modules`, and API module definitions that pass core's checks), an enabled database, management settings that conflict or lack ids, encryption (`aes` keys in `environment`, KMS key source, stages that never encrypt), a user config with which login works, `'ssm'` entries without `ssm.enable`, and keys that have no effect
|
|
128
|
-
4. Prints each problem with its JSON pointer and a fix; exits `1` when there are errors
|
|
129
|
-
|
|
130
|
-
**Example output:**
|
|
131
|
-
```
|
|
132
|
-
Validating /path/to/backend/index.js (stage: prod)
|
|
133
|
-
error /encrpytion Unknown key "encrpytion": nothing in Frigg reads it.
|
|
134
|
-
fix: Did you mean "encryption"?
|
|
135
|
-
error /database/postgres/management /database/postgres/management is "create-new", which is not an allowed value.
|
|
136
|
-
fix: Use one of: "discover", "managed", "use-existing".
|
|
137
|
-
warning /custom custom is not read by Frigg: it has no effect.
|
|
138
|
-
fix: Remove it.
|
|
139
|
-
✗ 2 error(s), 1 warning(s)
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
`--json` prints `{ valid, source, stage, errors, warnings }`; each issue is `{ severity, code, pointer, message, hint }`.
|
|
143
|
-
|
|
144
|
-
`frigg build` and `frigg deploy` run the same validation first and stop on errors (`--skip-validate` bypasses it, with a loud warning). `frigg start` runs it and only warns. `frigg init` validates the generated app the same way.
|
|
145
|
-
|
|
146
|
-
---
|
|
147
|
-
|
|
148
113
|
#### `frigg start [options]`
|
|
149
114
|
|
|
150
115
|
Start local development server with hot reload.
|
|
@@ -158,7 +123,7 @@ frigg start --frontend
|
|
|
158
123
|
```
|
|
159
124
|
|
|
160
125
|
**What it does:**
|
|
161
|
-
1. Validates DATABASE_URL environment variable
|
|
126
|
+
1. Validates DATABASE_URL environment variable
|
|
162
127
|
2. Detects database type (MongoDB or PostgreSQL)
|
|
163
128
|
3. Checks Prisma client generation status
|
|
164
129
|
4. Tests database connection
|
|
@@ -217,12 +182,10 @@ frigg deploy --region us-west-2
|
|
|
217
182
|
frigg deploy --force
|
|
218
183
|
frigg deploy --skip-env-validation
|
|
219
184
|
frigg deploy --skip-doctor # Skip health check (not recommended)
|
|
220
|
-
frigg deploy --skip-validate # Skip app definition validation (not recommended)
|
|
221
185
|
frigg deploy --no-interactive # CI/CD mode (no prompts, auto-repair safe issues)
|
|
222
186
|
```
|
|
223
187
|
|
|
224
188
|
**What it does:**
|
|
225
|
-
0. **Validates the app definition** (`frigg validate`) and stops on errors, unless `--skip-validate`
|
|
226
189
|
1. **Runs health check** (`frigg doctor`) to detect infrastructure issues
|
|
227
190
|
2. **Auto-repairs safe issues** (or prompts for confirmation in interactive mode)
|
|
228
191
|
3. **Fails if critical issues found** (unless `--skip-doctor` flag used)
|
|
@@ -14,9 +14,6 @@ jest.mock('child_process', () => ({
|
|
|
14
14
|
spawnSync: jest.fn()
|
|
15
15
|
}));
|
|
16
16
|
|
|
17
|
-
// The app definition validation step is tested in validate-command/.
|
|
18
|
-
jest.mock('../../../validate-command', () => ({ preflightValidation: jest.fn(() => true) }));
|
|
19
|
-
|
|
20
17
|
// Require after mocks
|
|
21
18
|
const { spawnSync } = require('child_process');
|
|
22
19
|
const { buildCommand } = require('../../../build-command');
|
|
@@ -10,9 +10,6 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
// Mock dependencies BEFORE requiring modules
|
|
13
|
-
// The app definition validation step is tested in validate-command/.
|
|
14
|
-
jest.mock('../../../validate-command', () => ({ preflightValidation: jest.fn(() => true) }));
|
|
15
|
-
|
|
16
13
|
jest.mock('child_process', () => ({
|
|
17
14
|
spawn: jest.fn()
|
|
18
15
|
}));
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
const { spawnSync } = require('child_process');
|
|
2
2
|
const path = require('path');
|
|
3
|
-
const { preflightValidation } = require('../validate-command');
|
|
4
3
|
|
|
5
4
|
async function buildCommand(options) {
|
|
6
5
|
console.log('Building the serverless application...');
|
|
7
6
|
|
|
8
|
-
// Validate the app definition first (ADR-051); errors stop the build.
|
|
9
|
-
if (!preflightValidation({ command: 'build', options, failOnErrors: true })) {
|
|
10
|
-
return;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
7
|
// Suppress AWS SDK warning message about maintenance mode
|
|
14
8
|
process.env.AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE = '1';
|
|
15
9
|
|
|
@@ -4,7 +4,6 @@ const fs = require('fs');
|
|
|
4
4
|
|
|
5
5
|
// Import doctor command for post-deployment health check
|
|
6
6
|
const { doctorCommand } = require('../doctor-command');
|
|
7
|
-
const { preflightValidation } = require('../validate-command');
|
|
8
7
|
|
|
9
8
|
// Configuration constants
|
|
10
9
|
const PATHS = {
|
|
@@ -313,11 +312,6 @@ async function pushOffloadedParametersOrAbort(appDefinition, options) {
|
|
|
313
312
|
async function deployCommand(options) {
|
|
314
313
|
console.log('Deploying the serverless application...');
|
|
315
314
|
|
|
316
|
-
// Validate the app definition first (ADR-051); errors stop the deploy.
|
|
317
|
-
if (!preflightValidation({ command: 'deploy', options, failOnErrors: true })) {
|
|
318
|
-
return;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
315
|
const appDefinition = loadAppDefinition();
|
|
322
316
|
const environment = validateAndBuildEnvironment(appDefinition, options);
|
|
323
317
|
|
package/frigg-cli/index.js
CHANGED
|
@@ -87,7 +87,6 @@ const { doctorCommand } = require('./doctor-command');
|
|
|
87
87
|
const { repairCommand } = require('./repair-command');
|
|
88
88
|
const { authCommand } = require('./auth-command');
|
|
89
89
|
const { ssmPushCommand } = require('./ssm-command');
|
|
90
|
-
const { validateCommand } = require('./validate-command');
|
|
91
90
|
|
|
92
91
|
const program = new Command();
|
|
93
92
|
|
|
@@ -109,24 +108,14 @@ program
|
|
|
109
108
|
.description('Run the backend and optional frontend')
|
|
110
109
|
.option('-s, --stage <stage>', 'deployment stage', 'dev')
|
|
111
110
|
.option('-v, --verbose', 'enable verbose output')
|
|
112
|
-
.option('--skip-validate', 'skip app definition validation')
|
|
113
111
|
.action(startCommand);
|
|
114
112
|
|
|
115
|
-
program
|
|
116
|
-
.command('validate')
|
|
117
|
-
.description('Validate the app definition (index.js) against the schema and the runtime rules')
|
|
118
|
-
.option('-s, --stage <stage>', 'also run the checks for this stage (encryption, deploy-time environment)')
|
|
119
|
-
.option('--json', 'print the report as JSON')
|
|
120
|
-
.option('-v, --verbose', 'enable verbose output')
|
|
121
|
-
.action(validateCommand);
|
|
122
|
-
|
|
123
113
|
program
|
|
124
114
|
.command('build')
|
|
125
115
|
.description('Build the serverless application')
|
|
126
116
|
.option('-s, --stage <stage>', 'deployment stage', 'dev')
|
|
127
117
|
.option('-v, --verbose', 'enable verbose output')
|
|
128
118
|
.option('-p, --production', 'build for production (enables AWS discovery)')
|
|
129
|
-
.option('--skip-validate', 'skip app definition validation (not recommended)')
|
|
130
119
|
.action(buildCommand);
|
|
131
120
|
|
|
132
121
|
program
|
|
@@ -136,7 +125,6 @@ program
|
|
|
136
125
|
.option('-v, --verbose', 'enable verbose output')
|
|
137
126
|
.option('-f, --force', 'force deployment (bypasses caching for layers and functions)')
|
|
138
127
|
.option('--skip-doctor', 'skip post-deployment health check')
|
|
139
|
-
.option('--skip-validate', 'skip app definition validation (not recommended)')
|
|
140
128
|
.action(deployCommand);
|
|
141
129
|
|
|
142
130
|
program
|
|
@@ -232,4 +220,4 @@ authProgram
|
|
|
232
220
|
|
|
233
221
|
program.parse(process.argv);
|
|
234
222
|
|
|
235
|
-
module.exports = { initCommand, installCommand, startCommand, buildCommand, deployCommand,
|
|
223
|
+
module.exports = { initCommand, installCommand, startCommand, buildCommand, deployCommand, generateIamCommand, uiCommand, dbSetupCommand, doctorCommand, repairCommand, authCommand, ssmPushCommand };
|
|
@@ -5,8 +5,7 @@ const { select, confirm, multiselect } = require('@inquirer/prompts');
|
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
6
|
const spawn = require('cross-spawn');
|
|
7
7
|
const npmRegistry = require('../utils/npm-registry');
|
|
8
|
-
const {
|
|
9
|
-
const { formatReport } = require('../validate-command/format-report');
|
|
8
|
+
const { validateAppDefinition, formatErrors } = require('@friggframework/schemas');
|
|
10
9
|
|
|
11
10
|
/**
|
|
12
11
|
* Backend-first template handler that treats frontend as optional demonstration
|
|
@@ -648,39 +647,61 @@ To integrate Frigg into your production application:
|
|
|
648
647
|
}
|
|
649
648
|
|
|
650
649
|
/**
|
|
651
|
-
* Validate
|
|
652
|
-
* `frigg validate`, `frigg build` and `frigg deploy` (ADR-051). Problems
|
|
653
|
-
* are reported as warnings: they never stop `frigg init`.
|
|
650
|
+
* Validate generated app definition against schema
|
|
654
651
|
*/
|
|
655
652
|
async validateGeneratedAppDefinition(appDefPath) {
|
|
656
653
|
try {
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
if (issues.length === 0) {
|
|
660
|
-
if (this.options.verbose) {
|
|
661
|
-
console.log(chalk.green('✅ App definition passes validation'));
|
|
662
|
-
}
|
|
663
|
-
return true;
|
|
654
|
+
if (this.options.verbose) {
|
|
655
|
+
console.log(chalk.gray('🔍 Validating app definition against schema...'));
|
|
664
656
|
}
|
|
665
|
-
|
|
666
|
-
|
|
657
|
+
|
|
658
|
+
// Read the generated index.js file
|
|
659
|
+
const content = await fs.readFile(appDefPath, 'utf8');
|
|
660
|
+
|
|
661
|
+
// Extract the appDefinition object (simplified approach)
|
|
662
|
+
// In a real scenario, we might use AST parsing for more robust extraction
|
|
663
|
+
const appDefinitionMatch = content.match(/const appDefinition = ({[\s\S]*?});/);
|
|
664
|
+
if (!appDefinitionMatch) {
|
|
665
|
+
throw new Error('Could not extract appDefinition from generated file');
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Create a minimal representation for validation
|
|
669
|
+
// Since we can't easily execute the file, we'll validate the structure we know we generated
|
|
670
|
+
const appDefinition = {
|
|
671
|
+
integrations: [], // Will be populated based on selected integrations
|
|
672
|
+
user: { password: true },
|
|
673
|
+
encryption: { fieldLevelEncryptionMethod: 'kms' },
|
|
674
|
+
vpc: { enable: true },
|
|
675
|
+
security: {
|
|
676
|
+
cors: {
|
|
677
|
+
origin: 'http://localhost:3000',
|
|
678
|
+
credentials: true
|
|
679
|
+
}
|
|
680
|
+
},
|
|
681
|
+
logging: { level: 'info', retentionInDays: 30 },
|
|
682
|
+
custom: {
|
|
683
|
+
appName: 'My Frigg Application',
|
|
684
|
+
version: '1.0.0',
|
|
685
|
+
environment: 'development'
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
|
|
689
|
+
// Validate against schema
|
|
690
|
+
const result = validateAppDefinition(appDefinition);
|
|
691
|
+
|
|
692
|
+
if (result.valid) {
|
|
667
693
|
if (this.options.verbose) {
|
|
668
|
-
console.log(chalk.
|
|
694
|
+
console.log(chalk.green('✅ App definition passes schema validation'));
|
|
669
695
|
}
|
|
670
696
|
return true;
|
|
697
|
+
} else {
|
|
698
|
+
console.log(chalk.yellow('⚠️ App definition has validation warnings:'));
|
|
699
|
+
console.log(chalk.gray(formatErrors(result.errors)));
|
|
700
|
+
return false;
|
|
671
701
|
}
|
|
672
|
-
console.log(chalk.yellow('⚠️ App definition validation:'));
|
|
673
|
-
console.log(
|
|
674
|
-
formatReport({
|
|
675
|
-
...report,
|
|
676
|
-
errors: [],
|
|
677
|
-
warnings: issues.map((issue) => ({ ...issue, severity: 'warning' })),
|
|
678
|
-
})
|
|
679
|
-
);
|
|
680
|
-
return report.errors.length === 0;
|
|
681
702
|
} catch (error) {
|
|
682
703
|
if (this.options.verbose) {
|
|
683
|
-
console.log(chalk.yellow(`⚠️
|
|
704
|
+
console.log(chalk.yellow(`⚠️ Schema validation skipped: ${error.message}`));
|
|
684
705
|
}
|
|
685
706
|
return true; // Don't fail the process for validation issues
|
|
686
707
|
}
|
|
@@ -12,7 +12,6 @@ const {
|
|
|
12
12
|
getDatabaseTypeNotConfiguredError,
|
|
13
13
|
getPrismaClientNotGeneratedError
|
|
14
14
|
} = require('../utils/error-messages');
|
|
15
|
-
const { preflightValidation } = require('../validate-command');
|
|
16
15
|
|
|
17
16
|
async function startCommand(options) {
|
|
18
17
|
if (options.verbose) {
|
|
@@ -26,9 +25,6 @@ async function startCommand(options) {
|
|
|
26
25
|
const envPath = path.join(process.cwd(), '.env');
|
|
27
26
|
dotenv.config({ path: envPath });
|
|
28
27
|
|
|
29
|
-
// Validate the app definition (ADR-051); local development only warns.
|
|
30
|
-
preflightValidation({ command: 'start', options, failOnErrors: false });
|
|
31
|
-
|
|
32
28
|
// Pre-flight database checks
|
|
33
29
|
try {
|
|
34
30
|
await performDatabaseChecks(options.verbose);
|
|
@@ -23,9 +23,6 @@ jest.mock('node:child_process', () => ({
|
|
|
23
23
|
}));
|
|
24
24
|
|
|
25
25
|
jest.mock('../utils/database-validator', () => mockValidator);
|
|
26
|
-
// The app definition validation step is tested in validate-command/.
|
|
27
|
-
jest.mock('../validate-command', () => ({ preflightValidation: jest.fn(() => true) }));
|
|
28
|
-
|
|
29
26
|
jest.mock('dotenv');
|
|
30
27
|
|
|
31
28
|
const { spawn } = require('node:child_process');
|
|
@@ -3,7 +3,6 @@ const fs = require('fs-extra');
|
|
|
3
3
|
const crypto = require('crypto');
|
|
4
4
|
const { composeServerlessDefinition } = require('./infrastructure-composer');
|
|
5
5
|
const { findNearestBackendPackageJson } = require('@friggframework/core');
|
|
6
|
-
const { applyAppDefinitionDefaults } = require('@friggframework/schemas');
|
|
7
6
|
|
|
8
7
|
// Filesystem-based cache to persist across osls require cache clears
|
|
9
8
|
const getCachePath = (backendDir) => {
|
|
@@ -103,9 +102,7 @@ async function createFriggInfrastructure() {
|
|
|
103
102
|
|
|
104
103
|
try {
|
|
105
104
|
const backend = require(backendFilePath);
|
|
106
|
-
|
|
107
|
-
// builders and the runtime see the same definition.
|
|
108
|
-
const appDefinition = applyAppDefinitionDefaults(backend.Definition);
|
|
105
|
+
const appDefinition = backend.Definition;
|
|
109
106
|
|
|
110
107
|
const definition = await composeServerlessDefinition(
|
|
111
108
|
appDefinition,
|
|
@@ -8,10 +8,10 @@ Frigg Framework supports automatic provisioning of Amazon Aurora Serverless v2 P
|
|
|
8
8
|
|
|
9
9
|
### Key Features
|
|
10
10
|
|
|
11
|
-
- **Aurora Serverless v2**: Cost-efficient auto-scaling database (0.5-
|
|
11
|
+
- **Aurora Serverless v2**: Cost-efficient auto-scaling database (0.5-1.0 ACU default)
|
|
12
12
|
- **VPC Integration**: Deployed in same private subnets as Lambda functions
|
|
13
13
|
- **Secrets Manager**: Automatic credential management and rotation
|
|
14
|
-
- **Three Management Modes**: discover,
|
|
14
|
+
- **Three Management Modes**: discover, create-new, use-existing
|
|
15
15
|
- **Security**: Private subnet deployment with security group isolation
|
|
16
16
|
- **High Availability**: Multi-AZ deployment with automatic failover
|
|
17
17
|
|
|
@@ -21,16 +21,12 @@ Frigg Framework supports automatic provisioning of Amazon Aurora Serverless v2 P
|
|
|
21
21
|
|
|
22
22
|
### App Definition Structure
|
|
23
23
|
|
|
24
|
-
These are the keys the Aurora builder reads (see `database.postgres` in
|
|
25
|
-
`packages/schemas/schemas/app-definition.schema.json`). `frigg validate`
|
|
26
|
-
rejects any other key under `database.postgres`.
|
|
27
|
-
|
|
28
24
|
```javascript
|
|
29
25
|
// backend/index.js
|
|
30
26
|
const appDefinition = {
|
|
31
27
|
name: 'my-frigg-app',
|
|
32
28
|
|
|
33
|
-
// VPC
|
|
29
|
+
// Enable VPC deployment (required for Aurora)
|
|
34
30
|
vpc: {
|
|
35
31
|
enable: true,
|
|
36
32
|
},
|
|
@@ -40,24 +36,34 @@ const appDefinition = {
|
|
|
40
36
|
postgres: {
|
|
41
37
|
enable: true,
|
|
42
38
|
|
|
43
|
-
// 'discover'
|
|
44
|
-
// Ignored when managementMode is 'managed' or 'existing'.
|
|
39
|
+
// Management mode: 'discover' | 'create-new' | 'use-existing'
|
|
45
40
|
management: 'discover',
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
// Basic Configuration
|
|
43
|
+
databaseName: 'frigg_db',
|
|
44
|
+
masterUsername: 'frigg_admin',
|
|
45
|
+
|
|
46
|
+
// Engine Configuration
|
|
47
|
+
engine: 'aurora-postgresql',
|
|
48
|
+
engineVersion: '15.3',
|
|
49
|
+
|
|
50
|
+
// Scaling Configuration (Aurora Serverless v2)
|
|
51
|
+
scaling: {
|
|
52
|
+
minCapacity: 0.5, // ACUs (0.5 = ~1GB RAM, ~$43/month)
|
|
53
|
+
maxCapacity: 1.0, // ACUs (1.0 = ~2GB RAM, ~$87/month)
|
|
54
|
+
},
|
|
50
55
|
|
|
51
|
-
//
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
// Backup Configuration
|
|
57
|
+
backupRetentionDays: 7,
|
|
58
|
+
preferredBackupWindow: '03:00-04:00',
|
|
54
59
|
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
// Security & Advanced
|
|
61
|
+
deletionProtection: true,
|
|
62
|
+
enablePerformanceInsights: false,
|
|
57
63
|
|
|
58
|
-
// use-existing
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
// For use-existing mode
|
|
65
|
+
clusterIdentifier: 'my-existing-cluster',
|
|
66
|
+
secretArn: 'arn:aws:secretsmanager:...',
|
|
61
67
|
}
|
|
62
68
|
}
|
|
63
69
|
};
|
|
@@ -67,17 +73,13 @@ module.exports = {
|
|
|
67
73
|
};
|
|
68
74
|
```
|
|
69
75
|
|
|
70
|
-
Backup retention (7 days), the backup and maintenance windows and deletion
|
|
71
|
-
settings are fixed by the builder and are not configurable through the app
|
|
72
|
-
definition.
|
|
73
|
-
|
|
74
76
|
---
|
|
75
77
|
|
|
76
78
|
## Management Modes
|
|
77
79
|
|
|
78
80
|
### 1. Discover Mode (Default)
|
|
79
81
|
|
|
80
|
-
|
|
82
|
+
Automatically discovers existing Aurora clusters or creates new one if none found.
|
|
81
83
|
|
|
82
84
|
```javascript
|
|
83
85
|
database: {
|
|
@@ -98,56 +100,63 @@ database: {
|
|
|
98
100
|
|
|
99
101
|
---
|
|
100
102
|
|
|
101
|
-
### 2.
|
|
103
|
+
### 2. Create-New Mode
|
|
102
104
|
|
|
103
|
-
|
|
105
|
+
Always creates a new Aurora cluster, even if existing clusters are found.
|
|
104
106
|
|
|
105
107
|
```javascript
|
|
106
108
|
database: {
|
|
107
109
|
postgres: {
|
|
108
110
|
enable: true,
|
|
109
|
-
management: '
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
management: 'create-new',
|
|
112
|
+
|
|
113
|
+
// Customization options
|
|
114
|
+
databaseName: 'my_app_db',
|
|
115
|
+
masterUsername: 'admin',
|
|
116
|
+
engineVersion: '15.3',
|
|
117
|
+
scaling: {
|
|
118
|
+
minCapacity: 1.0,
|
|
119
|
+
maxCapacity: 2.0,
|
|
120
|
+
},
|
|
121
|
+
backupRetentionDays: 14,
|
|
122
|
+
deletionProtection: true,
|
|
112
123
|
}
|
|
113
124
|
}
|
|
114
125
|
```
|
|
115
126
|
|
|
116
|
-
With the top-level `managementMode: 'managed'` (and `vpcIsolation: 'isolated'`),
|
|
117
|
-
Frigg manages the database per stage and `database.postgres.management` is ignored.
|
|
118
|
-
|
|
119
127
|
**Best For**: Production environments where you want dedicated database resources.
|
|
120
128
|
|
|
121
129
|
---
|
|
122
130
|
|
|
123
131
|
### 3. Use-Existing Mode
|
|
124
132
|
|
|
125
|
-
|
|
133
|
+
Uses a specific existing Aurora cluster by identifier.
|
|
126
134
|
|
|
127
135
|
```javascript
|
|
128
136
|
database: {
|
|
129
137
|
postgres: {
|
|
130
138
|
enable: true,
|
|
131
139
|
management: 'use-existing',
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
140
|
+
|
|
141
|
+
// Required: existing cluster identifier
|
|
142
|
+
clusterIdentifier: 'my-existing-aurora-cluster',
|
|
143
|
+
|
|
144
|
+
// Optional: secret ARN (discovered if not provided)
|
|
145
|
+
secretArn: 'arn:aws:secretsmanager:us-east-1:123456789012:secret:my-db-secret',
|
|
146
|
+
|
|
147
|
+
// Database name to connect to
|
|
148
|
+
databaseName: 'frigg_db',
|
|
136
149
|
}
|
|
137
150
|
}
|
|
138
151
|
```
|
|
139
152
|
|
|
140
|
-
To use an existing cluster by identifier instead, use the ownership form:
|
|
141
|
-
`ownership: { cluster: 'external', instance: 'external' }` with
|
|
142
|
-
`external: { clusterIdentifier, instanceIdentifier, secretArn }`.
|
|
143
|
-
|
|
144
153
|
**Best For**: Shared database scenarios or when you manage Aurora outside of Frigg.
|
|
145
154
|
|
|
146
155
|
---
|
|
147
156
|
|
|
148
157
|
## Created AWS Resources
|
|
149
158
|
|
|
150
|
-
When provisioning Aurora (`
|
|
159
|
+
When provisioning Aurora (`create-new` or `discover` mode without existing cluster), Frigg creates:
|
|
151
160
|
|
|
152
161
|
### 1. RDS DB Subnet Group
|
|
153
162
|
- **Name**: `{service}-{stage}-db-subnet-group`
|
|
@@ -212,15 +221,17 @@ database: {
|
|
|
212
221
|
database: {
|
|
213
222
|
postgres: {
|
|
214
223
|
enable: true,
|
|
215
|
-
|
|
216
|
-
|
|
224
|
+
scaling: {
|
|
225
|
+
minCapacity: 1.0, // Higher baseline for production
|
|
226
|
+
maxCapacity: 4.0, // Handle traffic spikes
|
|
227
|
+
},
|
|
228
|
+
backupRetentionDays: 30, // Longer retention
|
|
229
|
+
enablePerformanceInsights: true, // Monitoring
|
|
230
|
+
deletionProtection: true, // Prevent accidental deletion
|
|
217
231
|
}
|
|
218
232
|
}
|
|
219
233
|
```
|
|
220
234
|
|
|
221
|
-
Backup retention, Performance Insights and deletion protection are not
|
|
222
|
-
configurable through the app definition; change them on the cluster.
|
|
223
|
-
|
|
224
235
|
**Estimated Monthly Costs**:
|
|
225
236
|
- **Baseline**: $87/month (1.0 ACU minimum)
|
|
226
237
|
- **Peak Traffic**: $348/month (4.0 ACU maximum)
|
|
@@ -265,9 +276,15 @@ const users = await prismaClient.user.findMany();
|
|
|
265
276
|
|
|
266
277
|
### 4. Deletion Protection
|
|
267
278
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
279
|
+
```javascript
|
|
280
|
+
database: {
|
|
281
|
+
postgres: {
|
|
282
|
+
deletionProtection: true, // Prevents accidental deletion
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Important**: When enabled, you must manually disable deletion protection in AWS console before stack deletion.
|
|
271
288
|
|
|
272
289
|
---
|
|
273
290
|
|
|
@@ -367,7 +384,7 @@ DB_TYPE=postgresql
|
|
|
367
384
|
database: {
|
|
368
385
|
postgres: {
|
|
369
386
|
enable: true,
|
|
370
|
-
management: '
|
|
387
|
+
management: 'create-new',
|
|
371
388
|
}
|
|
372
389
|
}
|
|
373
390
|
```
|
|
@@ -394,7 +411,7 @@ DB_TYPE=postgresql
|
|
|
394
411
|
database: {
|
|
395
412
|
postgres: {
|
|
396
413
|
enable: true,
|
|
397
|
-
management: '
|
|
414
|
+
management: 'create-new',
|
|
398
415
|
}
|
|
399
416
|
}
|
|
400
417
|
```
|
|
@@ -439,13 +456,13 @@ DB_TYPE=postgresql
|
|
|
439
456
|
|
|
440
457
|
**Error**:
|
|
441
458
|
```
|
|
442
|
-
No Aurora cluster found in discovery mode. Set management to "
|
|
459
|
+
No Aurora cluster found in discovery mode. Set management to "create-new"...
|
|
443
460
|
```
|
|
444
461
|
|
|
445
462
|
**Solution**:
|
|
446
463
|
1. Check VPC is enabled: `vpc.enable: true`
|
|
447
|
-
2. Set management mode: `management: '
|
|
448
|
-
3. Or
|
|
464
|
+
2. Set management mode: `management: 'create-new'`
|
|
465
|
+
3. Or provide cluster identifier: `clusterIdentifier: 'my-cluster'`
|
|
449
466
|
|
|
450
467
|
---
|
|
451
468
|
|
|
@@ -527,19 +544,40 @@ Cannot create Aurora cluster: InsufficientDBInstanceCapacity
|
|
|
527
544
|
|
|
528
545
|
## Advanced Configuration
|
|
529
546
|
|
|
530
|
-
### Custom
|
|
547
|
+
### Custom Backup Window
|
|
531
548
|
|
|
532
549
|
```javascript
|
|
533
550
|
database: {
|
|
534
551
|
postgres: {
|
|
535
552
|
enable: true,
|
|
536
|
-
|
|
553
|
+
backupRetentionDays: 30,
|
|
554
|
+
preferredBackupWindow: '02:00-03:00', // UTC
|
|
537
555
|
}
|
|
538
556
|
}
|
|
539
557
|
```
|
|
540
558
|
|
|
541
|
-
|
|
542
|
-
|
|
559
|
+
### Enhanced Monitoring
|
|
560
|
+
|
|
561
|
+
```javascript
|
|
562
|
+
database: {
|
|
563
|
+
postgres: {
|
|
564
|
+
enable: true,
|
|
565
|
+
enablePerformanceInsights: true,
|
|
566
|
+
// Performance Insights retention: 7 days (default) or 731 days
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Custom Engine Version
|
|
572
|
+
|
|
573
|
+
```javascript
|
|
574
|
+
database: {
|
|
575
|
+
postgres: {
|
|
576
|
+
enable: true,
|
|
577
|
+
engineVersion: '14.6', // Default: 15.3
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
```
|
|
543
581
|
|
|
544
582
|
### Read Replicas (Not Supported Yet)
|
|
545
583
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/devtools",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.
|
|
4
|
+
"version": "2.0.0--canary.668.8e53aa9.0",
|
|
5
5
|
"bin": {
|
|
6
6
|
"frigg": "./frigg-cli/index.js"
|
|
7
7
|
},
|
|
@@ -26,9 +26,9 @@
|
|
|
26
26
|
"@babel/eslint-parser": "^7.18.9",
|
|
27
27
|
"@babel/parser": "^7.25.3",
|
|
28
28
|
"@babel/traverse": "^7.25.3",
|
|
29
|
-
"@friggframework/core": "2.0.0--canary.
|
|
30
|
-
"@friggframework/schemas": "2.0.0--canary.
|
|
31
|
-
"@friggframework/test": "2.0.0--canary.
|
|
29
|
+
"@friggframework/core": "2.0.0--canary.668.8e53aa9.0",
|
|
30
|
+
"@friggframework/schemas": "2.0.0--canary.668.8e53aa9.0",
|
|
31
|
+
"@friggframework/test": "2.0.0--canary.668.8e53aa9.0",
|
|
32
32
|
"@hapi/boom": "^10.0.1",
|
|
33
33
|
"@inquirer/prompts": "^5.3.8",
|
|
34
34
|
"axios": "^1.18.0",
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"validate-npm-package-name": "^5.0.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
60
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
59
|
+
"@friggframework/eslint-config": "2.0.0--canary.668.8e53aa9.0",
|
|
60
|
+
"@friggframework/prettier-config": "2.0.0--canary.668.8e53aa9.0",
|
|
61
61
|
"aws-sdk-client-mock": "^4.1.0",
|
|
62
62
|
"aws-sdk-client-mock-jest": "^4.1.0",
|
|
63
63
|
"jest": "^30.1.3",
|
|
@@ -89,5 +89,5 @@
|
|
|
89
89
|
"publishConfig": {
|
|
90
90
|
"access": "public"
|
|
91
91
|
},
|
|
92
|
-
"gitHead": "
|
|
92
|
+
"gitHead": "8e53aa9648ec5861382722f8bc9716c8d6024ec4"
|
|
93
93
|
}
|