@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.
Files changed (26) hide show
  1. package/frigg-cli/README.md +1 -38
  2. package/frigg-cli/__tests__/unit/commands/build.test.js +0 -3
  3. package/frigg-cli/__tests__/unit/commands/deploy.test.js +0 -3
  4. package/frigg-cli/build-command/index.js +0 -6
  5. package/frigg-cli/deploy-command/index.js +0 -6
  6. package/frigg-cli/index.js +1 -13
  7. package/frigg-cli/init-command/backend-first-handler.js +46 -25
  8. package/frigg-cli/start-command/index.js +0 -4
  9. package/frigg-cli/start-command/start-command.test.js +0 -3
  10. package/infrastructure/create-frigg-infrastructure.js +1 -4
  11. package/infrastructure/docs/POSTGRES-CONFIGURATION.md +98 -60
  12. package/package.json +7 -7
  13. package/frigg-cli/__tests__/unit/commands/validate-wiring.test.js +0 -92
  14. package/frigg-cli/validate-command/__tests__/init-validation.test.js +0 -63
  15. package/frigg-cli/validate-command/__tests__/integrations-checks.test.js +0 -133
  16. package/frigg-cli/validate-command/__tests__/validate-app-definition.test.js +0 -326
  17. package/frigg-cli/validate-command/__tests__/validate-command.test.js +0 -241
  18. package/frigg-cli/validate-command/checks/config.js +0 -468
  19. package/frigg-cli/validate-command/checks/integrations.js +0 -274
  20. package/frigg-cli/validate-command/format-report.js +0 -58
  21. package/frigg-cli/validate-command/index.js +0 -107
  22. package/frigg-cli/validate-command/load-app-definition.js +0 -93
  23. package/frigg-cli/validate-command/schema-issues.js +0 -154
  24. package/frigg-cli/validate-command/validate-app-definition.js +0 -60
  25. package/infrastructure/app-definition-schema-contract.test.js +0 -607
  26. package/infrastructure/create-frigg-infrastructure.test.js +0 -51
@@ -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, and the app definition (`frigg validate`; problems are printed as warnings, `--skip-validate` skips it)
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
 
@@ -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, validateCommand, generateIamCommand, uiCommand, dbSetupCommand, doctorCommand, repairCommand, authCommand, ssmPushCommand };
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 { runValidation } = require('../validate-command');
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 the generated app definition with the same code path as
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
- const report = runValidation({ cwd: path.dirname(appDefPath) });
658
- const issues = [...report.errors, ...report.warnings];
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
- if (report.errors.length === 1 && report.errors[0].code === 'load-failed') {
666
- // Before `npm install`, index.js cannot load its dependencies yet.
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.gray('App definition not validated yet: run `frigg validate` after `npm install`.'));
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(`⚠️ Validation skipped: ${error.message}`));
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
- // Same defaults step as core's loadAppDefinition (ADR-051), so the
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-4 ACU default)
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, managed, use-existing
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 Configuration (required for Aurora)
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' (also when omitted) | 'managed' | 'use-existing'
44
- // Ignored when managementMode is 'managed' or 'existing'.
39
+ // Management mode: 'discover' | 'create-new' | 'use-existing'
45
40
  management: 'discover',
46
41
 
47
- database: 'frigg', // database name (default 'frigg')
48
- username: 'postgres', // master user (default 'postgres')
49
- engineVersion: '15.13', // Aurora PostgreSQL version (default '15.13')
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
- // Aurora Serverless v2 capacity, in ACUs (0.5-128)
52
- minCapacity: 0.5, // default 0.5
53
- maxCapacity: 4, // default 4
56
+ // Backup Configuration
57
+ backupRetentionDays: 7,
58
+ preferredBackupWindow: '03:00-04:00',
54
59
 
55
- publiclyAccessible: false, // default false (private subnets)
56
- autoCreateCredentials: false, // discover only: create a secret for a discovered cluster
60
+ // Security & Advanced
61
+ deletionProtection: true,
62
+ enablePerformanceInsights: false,
57
63
 
58
- // use-existing only
59
- // endpoint: 'mydb.cluster-abc123.us-east-1.rds.amazonaws.com',
60
- // port: 5432,
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
- Discovers an existing Aurora cluster, or creates a new one in the stack if none is found.
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. Managed Mode
103
+ ### 2. Create-New Mode
102
104
 
103
- Creates the cluster, instance, subnet group and secret in the stack.
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: 'managed',
110
- minCapacity: 1,
111
- maxCapacity: 2,
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
- Connects to an existing PostgreSQL endpoint without creating database resources.
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
- endpoint: 'my-cluster.cluster-abc123.us-east-1.rds.amazonaws.com', // required
133
- port: 5432,
134
- database: 'frigg_db',
135
- username: 'frigg_admin',
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 (`managed`, or `discover` mode without an existing cluster), Frigg creates:
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
- minCapacity: 1, // Higher baseline for production
216
- maxCapacity: 4, // Handle traffic spikes
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
- Deletion protection is not configurable through the app definition. Enable it
269
- on the cluster in the AWS console (or with the AWS CLI); you must then disable
270
- it before deleting the stack.
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: 'managed',
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: 'managed',
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 "managed" or provide endpoint with "use-existing".
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: 'managed'`
448
- 3. Or connect to a known endpoint: `management: 'use-existing'`, `endpoint: '...'`
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 Engine Version
547
+ ### Custom Backup Window
531
548
 
532
549
  ```javascript
533
550
  database: {
534
551
  postgres: {
535
552
  enable: true,
536
- engineVersion: '16.4', // Default: 15.13
553
+ backupRetentionDays: 30,
554
+ preferredBackupWindow: '02:00-03:00', // UTC
537
555
  }
538
556
  }
539
557
  ```
540
558
 
541
- The backup window, backup retention and Performance Insights are set by the
542
- builder and are not configurable through the app definition.
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.666.81647c4.0",
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.666.81647c4.0",
30
- "@friggframework/schemas": "2.0.0--canary.666.81647c4.0",
31
- "@friggframework/test": "2.0.0--canary.666.81647c4.0",
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.666.81647c4.0",
60
- "@friggframework/prettier-config": "2.0.0--canary.666.81647c4.0",
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": "81647c4f85dd9b1e8e69b2bddcb09b1759341bf8"
92
+ "gitHead": "8e53aa9648ec5861382722f8bc9716c8d6024ec4"
93
93
  }