Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion 3 .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ node_modules

# sst
.sst
.build

# opennext
.open-next
Expand All @@ -16,3 +15,5 @@ node_modules

# editor files
.vim

.env
36 changes: 22 additions & 14 deletions 36 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,60 +8,68 @@ We create a note taking app from scratch — [**demo.sst.dev**](https://demo.sst

We use React.js, AWS Lambda, API Gateway, DynamoDB, and Cognito. This repo is a full-stack serverless app built with [SST](https://github.com/sst/sst).

- The `stacks/` directory defines our AWS infrastructure using AWS CDK.
- The `infra/` directory defines our AWS infrastructure.
- The `packages/functions` directory contains the Lambda functions that power the CRUD API.
- The `packages/frontend` directory contains the React app.

It's a single-page React app powered by a serverless CRUD API. We also cover how add user authentication, handle file uploads, and process credit card payments with Stripe.

### Prerequisites

Before you get started:

1. [Configure your AWS credentials](https://docs.sst.dev/advanced/iam-credentials#loading-from-a-file)
2. [Install the SST CLI](https://ion.sst.dev/docs/reference/cli/)

### Usage

Clone this repo.

```bash
$ git clone https://github.com/sst/demo-notes-app
git clone -b ion https://github.com/sst/demo-notes-app.git
```

Install dependencies.

```bash
$ pnpm install
npm install
```

This project uses a secret that we are not checking in to the repo. Make sure to [create one before deploying](https://sst.dev/chapters/handling-secrets-in-sst.html).

```bash
$ pnpm sst secrets set STRIPE_SECRET_KEY <YOUR STRIPE SECRET TEST KEY>
sst secret set StripeSecretKey <YOUR STRIPE SECRET TEST KEY>
```

#### Developing Locally

Start the [Live Lambda Dev Environment](https://docs.sst.dev/live-lambda-development).
Start the React local dev environment from the `packages/frontend/` dir.

```bash
$ pnpm sst dev
```

Start the React local dev environment from the `packges/frontend/` dir.

```bash
$ pnpm run dev
cd packages/frontend/
npm run dev
```

#### Running Tests

From the project root.

```bash
$ pnpm test
npm test
```

#### Deploying to Prod

Run this in the project root to deploy it to prod.

```bash
$ pnpm sst deploy --stage prod
sst deploy --stage production
```

Make sure to set your secret for prod as well.

```bash
sst secret set StripeSecretKey <YOUR STRIPE SECRET TEST KEY> --stage production
```

---
Expand Down
22 changes: 22 additions & 0 deletions 22 infra/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { table, secret } from "./storage";

// Create the API
export const api = new sst.aws.ApiGatewayV2("Api", {
transform: {
route: {
handler: {
link: [table, secret],
},
args: {
auth: { iam: true }
},
}
}
});

api.route("GET /notes", "packages/functions/src/list.main");
api.route("POST /notes", "packages/functions/src/create.main");
api.route("GET /notes/{id}", "packages/functions/src/get.main");
api.route("PUT /notes/{id}", "packages/functions/src/update.main");
api.route("DELETE /notes/{id}", "packages/functions/src/delete.main");
api.route("POST /billing", "packages/functions/src/billing.main");
45 changes: 45 additions & 0 deletions 45 infra/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { api } from "./api";
import { bucket } from "./storage";

const region = aws.getRegionOutput().name;

export const userPool = new sst.aws.CognitoUserPool("MyUserPool", {
usernames: ["email"]
});

export const userPoolClient = userPool.addClient("MyUserPoolClient");

export const identityPool = new sst.aws.CognitoIdentityPool("MyIdentityPool", {
userPools: [
{
userPool: userPool.id,
client: userPoolClient.id,
},
],
permissions: {
authenticated: [
{
actions: ["s3:*"],
resources: [
$concat(bucket.arn, "/private/${cognito-identity.amazonaws.com:sub}/*"),
],
},
{
actions: [
"execute-api:*",
],
resources: [
$concat(
"arn:aws:execute-api:",
region,
":",
aws.getCallerIdentityOutput({}).accountId,
":",
api.nodes.api.id,
"/*/*/*"
),
],
},
],
},
});
24 changes: 24 additions & 0 deletions 24 infra/frontend.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { api } from "./api";
import { bucket } from "./storage";
import { userPool, identityPool, userPoolClient } from "./auth";

const region = aws.getRegionOutput().name;

export const web = new sst.aws.StaticSite("Web", {
path: "packages/frontend",
build: {
output: "dist",
command: "npm run build",
},
// NOTE: Disabling custom domains for now
// domain: $app.stage === "production" ? "demo.sst.dev" : undefined,
environment: {
VITE_REGION: region,
VITE_API_URL: api.url,
VITE_BUCKET: bucket.name,
VITE_USER_POOL_ID: userPool.id,
VITE_IDENTITY_POOL_ID: identityPool.id,
VITE_USER_POOL_CLIENT_ID: userPoolClient.id,
},
});

14 changes: 14 additions & 0 deletions 14 infra/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Create an S3 bucket
export const bucket = new sst.aws.Bucket("Uploads");

// Create the DynamoDB table
export const table = new sst.aws.Dynamo("Notes", {
fields: {
userId: "string",
noteId: "string",
},
primaryIndex: { hashKey: "userId", rangeKey: "noteId" },
});

// Create a secret for Stripe
export const secret = new sst.Secret("StripeSecretKey");
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.