Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
87e8390
feat: avatar s3 feature for discussions app
9pace Jan 15, 2026
7474e4e
feat(cli): generate per-table stacks for multiple DDB tables
9pace Mar 17, 2026
76b4799
fix(discussions): replace hand-crafted snapshots with real infrastruc…
9pace Mar 18, 2026
5ef66e7
docs(discussions): add bookmarks table setup instructions to README
9pace Mar 18, 2026
bc3ac52
fix(discussions): sanitize Amplify App ID in Gen2 snapshot files
9pace Mar 18, 2026
c373245
Merge remote-tracking branch 'origin/discussions-s3' into multi-ddb-p…
9pace Mar 20, 2026
c1da85b
docs(discussions): add S3 avatars bucket to migration config
9pace Mar 20, 2026
2a28a87
test(discussions): update snapshots with S3 avatars + bookmarks DDB
9pace Mar 20, 2026
22f9896
fix(cli): disambiguate S3 nested stack from DDB per-table stacks
9pace Mar 20, 2026
6e65d9c
fix(cli): address PR review comments for per-table stacks
9pace Mar 23, 2026
ed1fc15
fix(cli): restore storage:S3 case in validateSingleResourcePerStack
9pace Mar 23, 2026
150d44e
chore(cli): merge gen2-migration into multi-ddb-per-table-stacks
9pace Mar 23, 2026
d207e68
feat(cli): add S3 avatars and bookmarks DDB tests to discussions test…
9pace Mar 23, 2026
6b794c1
refactor(cli): clean up bookmarks test - shared DDB client, config-ba…
9pace Mar 23, 2026
1aceadb
chore(cli): remove dev-only .gitignore from amplify-cli package
9pace Mar 23, 2026
a514ec7
fix(cli): add typescript devDep to fix typecheck for bundler moduleRe…
9pace Mar 24, 2026
51ad9c8
fix: use README-specified emailVerificationMessage in discussions sna…
9pace Mar 24, 2026
9c4665b
fix: replace remaining old verification message in discussions snapshots
9pace Mar 24, 2026
91af8a4
fix: align gen2 branch verification messages with README
9pace Mar 24, 2026
3552a55
fix: revert SMS verification messages to original values
9pace Mar 24, 2026
46cc7a8
fix: remove trailing newlines from parameters files
9pace Mar 24, 2026
b3fe56e
fix: remove unnecessary typescript devDependency from migration apps
9pace Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 62 additions & 5 deletions amplify-migration-apps/discussions/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

![](./images/app.png)

A discussion application built featuring authentication, GraphQL API, Lambda functions, and DynamoDB storage.
A discussion application built featuring authentication, GraphQL API, Lambda functions, multiple DynamoDB storage tables (activity + bookmarks), and S3.

> [!NOTICE]
> Since amplify operations add files to your local directory, its better not to operate within this repo.
Expand Down Expand Up @@ -116,8 +116,9 @@ amplify add api

### Storage

DynamoDB table for storing user activity logs with partition key, sort key,
and global secondary index for querying by activity type.
Two DynamoDB tables: `activity` for storing user activity logs, and `bookmarks` for storing user bookmarks on posts.

#### Activity Table

```console
amplify add storage
Expand Down Expand Up @@ -169,6 +170,59 @@ https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.Core
✔ Do you want to add a Lambda Trigger for your Table? (y/N) · no
```

#### Bookmarks Table

```console
amplify add storage
```

```console
? Select from one of the below mentioned services: NoSQL Database

Welcome to the NoSQL DynamoDB database wizard
This wizard asks you a series of questions to help determine how to set up your NoSQL database table.

✔ Provide a friendly name · bookmarks
✔ Provide table name · bookmarks

You can now add columns to the table.

✔ What would you like to name this column · userId
✔ Choose the data type · string
✔ Would you like to add another column? (Y/n) · yes
✔ What would you like to name this column · postId
✔ Choose the data type · string
✔ Would you like to add another column? (Y/n) · no

✔ Choose partition key for the table · userId
✔ Do you want to add a sort key to your table? (Y/n) · yes
✔ Choose sort key for the table · postId

✔ Do you want to add global secondary indexes to your table? (Y/n) · yes
✔ Provide the GSI name · byPost
✔ Choose partition key for the GSI · postId
✔ Do you want to add a sort key to your global secondary index? (Y/n) · no
✔ Do you want to add more global secondary indexes to your table? (Y/n) · no
✔ Do you want to add a Lambda Trigger for your Table? (y/N) · no
```

### Storage (S3 Avatars)

S3 bucket for storing user profile pictures.

```console
amplify add storage
```

```console
? Select from one of the below mentioned services: Content (Images, audio, video, etc.)
✔ Provide a friendly name for your resource that will be used to label this category in the project: · avatars
✔ Provide bucket name: · discus-avatars
✔ Who should have access: · Auth users only
✔ What kind of access do you want for Authenticated users? · create/update, read, delete
✔ Do you want to add a Lambda Trigger for your S3 Bucket? (y/N) · no
```

### Function

**Node.js Lambda function that retrieves user activity from DynamoDB storage.**
Expand Down Expand Up @@ -280,6 +334,10 @@ amplify push
├──────────┼─────────────────────────────┼───────────┼───────────────────┤
│ Storage │ activity │ Create │ awscloudformation │
├──────────┼─────────────────────────────┼───────────┼───────────────────┤
│ Storage │ bookmarks │ Create │ awscloudformation │
├──────────┼─────────────────────────────┼───────────┼───────────────────┤
│ Storage │ avatars │ Create │ awscloudformation │
├──────────┼─────────────────────────────┼───────────┼───────────────────┤
│ Function │ fetchuseractivity │ Create │ awscloudformation │
├──────────┼─────────────────────────────┼───────────┼───────────────────┤
│ Function │ recorduseractivity │ Create │ awscloudformation │
Expand Down Expand Up @@ -332,7 +390,7 @@ this process for any number of users.

> Based on https://github.com/aws-amplify/amplify-cli/blob/gen2-migration/GEN2_MIGRATION_GUIDE.md

First and install the experimental CLI package the provides the new commands:
First install the experimental amplify CLI package that provides the migration commands.

```console
npm install --no-save @aws-amplify/cli-internal-gen2-migration-experimental-alpha
Expand Down Expand Up @@ -419,4 +477,3 @@ git push origin gen2-main
```

Wait for the deployment to finish successfully.

Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import { auth } from './auth/resource';
import { data } from './data/resource';
import { storage } from './storage/resource';
import { fetchuseractivity } from './storage/fetchuseractivity/resource';
import { recorduseractivity } from './storage/recorduseractivity/resource';
import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { StartingPosition } from 'aws-cdk-lib/aws-lambda';
import {
Table,
AttributeType,
BillingMode,
StreamViewType,
} from 'aws-cdk-lib/aws-dynamodb';
import { DynamoEventSource } from 'aws-cdk-lib/aws-lambda-event-sources';
import { StartingPosition } from 'aws-cdk-lib/aws-lambda';
import { defineBackend } from '@aws-amplify/backend';
import { Duration } from 'aws-cdk-lib';

const backend = defineBackend({
auth,
data,
storage,
fetchuseractivity,
recorduseractivity,
});
const storageStack = backend.createStack('storage');
const activity = new Table(storageStack, 'activity', {
const storageActivityStack = backend.createStack('storageactivity');
const activity = new Table(storageActivityStack, 'activity', {
partitionKey: { name: 'id', type: AttributeType.STRING },
billingMode: BillingMode.PROVISIONED,
readCapacity: 5,
Expand All @@ -36,6 +38,22 @@ activity.addGlobalSecondaryIndex({
readCapacity: 5,
writeCapacity: 5,
});
const storageBookmarksStack = backend.createStack('storagebookmarks');
const bookmarks = new Table(storageBookmarksStack, 'bookmarks', {
partitionKey: { name: 'userId', type: AttributeType.STRING },
billingMode: BillingMode.PROVISIONED,
readCapacity: 5,
writeCapacity: 5,
stream: StreamViewType.NEW_IMAGE,
sortKey: { name: 'postId', type: AttributeType.STRING },
});
// Add this property to the Table above post refactor: tableName: 'bookmarks-main'
bookmarks.addGlobalSecondaryIndex({
indexName: 'byPost',
partitionKey: { name: 'postId', type: AttributeType.STRING },
readCapacity: 5,
writeCapacity: 5,
});
const cfnUserPool = backend.auth.resources.cfnResources.cfnUserPool;
cfnUserPool.usernameAttributes = ['phone_number'];
cfnUserPool.policies = {
Expand Down Expand Up @@ -125,3 +143,16 @@ for (const model of ['Topic', 'Post', 'Comment']) {
backend.recorduseractivity.resources.lambda.role!
);
}
const s3Bucket = backend.storage.resources.cfnResources.cfnBucket;
// Use this bucket name post refactor
// s3Bucket.bucketName = 'discus-avatarsc39a5-main';
s3Bucket.bucketEncryption = {
serverSideEncryptionConfiguration: [
{
serverSideEncryptionByDefault: {
sseAlgorithm: 'AES256',
},
bucketKeyEnabled: false,
},
],
};
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ export const data = defineData({
//The "branchname" variable needs to be the same as your deployment branch if you want to reuse your Gen1 app tables
branchName: 'main',
modelNameToTableNameMapping: {
Topic: 'Topic-ruiylk7rjnb4ziygno3jh4wrsq-main',
Post: 'Post-ruiylk7rjnb4ziygno3jh4wrsq-main',
Comment: 'Comment-ruiylk7rjnb4ziygno3jh4wrsq-main',
Topic: 'Topic-u3jn2qbupzbyhc3h53673wdvim-main',
Post: 'Post-u3jn2qbupzbyhc3h53673wdvim-main',
Comment: 'Comment-u3jn2qbupzbyhc3h53673wdvim-main',
},
},
],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineStorage } from '@aws-amplify/backend';

const branchName = process.env.AWS_BRANCH ?? 'sandbox';

export const storage = defineStorage({
name: `discus-avatarsc39a5-${branchName}`,
access: (allow) => ({
'public/*': [allow.authenticated.to(['write', 'read', 'delete'])],
'protected/{entity_id}/*': [
allow.authenticated.to(['write', 'read', 'delete']),
],
'private/{entity_id}/*': [
allow.authenticated.to(['write', 'read', 'delete']),
],
}),
});

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
[
{
"Source": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX",
"LogicalResourceId": "amplifyAuthUserPool4BA7F805"
},
"Destination": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX-holding",
"LogicalResourceId": "amplifyAuthUserPool4BA7F805"
}
},
{
"Source": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX",
"LogicalResourceId": "amplifyAuthUserPoolNativeAppClient79534448"
},
"Destination": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX-holding",
"LogicalResourceId": "amplifyAuthUserPoolNativeAppClient79534448"
}
},
{
"Source": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX",
"LogicalResourceId": "amplifyAuthUserPoolAppClient2626C6F8"
},
"Destination": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX-holding",
"LogicalResourceId": "amplifyAuthUserPoolAppClient2626C6F8"
}
},
{
"Source": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX",
"LogicalResourceId": "amplifyAuthIdentityPool3FDE84CC"
},
"Destination": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX-holding",
"LogicalResourceId": "amplifyAuthIdentityPool3FDE84CC"
}
},
{
"Source": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX",
"LogicalResourceId": "amplifyAuthIdentityPoolRoleAttachment045F17C8"
},
"Destination": {
"StackName": "amplify-discussions-gen2main-branch-a27e51c30a-auth179371D7-6NIMXK30VQKX-holding",
"LogicalResourceId": "amplifyAuthIdentityPoolRoleAttachment045F17C8"
}
}
]
Loading
Loading