Code Monkey home page Code Monkey logo

seed's People

Contributors

anhbaonguyenle avatar eirene avatar phuong150922 avatar silver-times avatar spy4x avatar urnix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

seed's Issues

fix(back): prevent an exception in an EventHandler to kill execution for all future event handlers

Problem:
If an exception is raised in an event handler - it kills the execution pipe for all other event handlers.
But the application survives that and keeps running, just without any event handlers execution.

A solution might be to add a try-catch block in a proper place (to EventBusExt? or implement a BaseEventHandler class?).

try {
  this.handle(fn)
} catch (error: unknown) {
  logSegment.error({ error: error as Error });
}

feat(back-api): ensure environment variables are presented

Right now application just "trusts" the environment that all required variables are presented. Which leads to exceptions being raised later on if some of them are missing.

We need a functions that checks if environment is presented and throws an error if it's not.

Before:

export const API_CONFIG = {
redisHost: process.env['REDIS_HOST'] as string,
// ... other vars
};

After:

export const API_CONFIG = {
redisHost: getEnv('REDIS_HOST'),
// ... other vars
};

function getEnv(name: string): string {
  const value = process.env[name];
  if(!value) {
    throw new Error(`Environment variable ${name} is misssing`);
  }
  return value;
}

Router: Protect routes with Guards

  • Should keep code inside front-shared-auth library?
  • AngularFire build-in guards?
  • IsAuthenticatedGuard (redirects to /auth)
  • IsNotAuthenticatedGuard (redirects to /profile)

feat(front,back): remove field "userName"

Reason:

it's rarely used by SaaS startups, mostly by social networks.

Parts:

  1. Backend endpoint @Get('is-username-free/:userName')
  2. DTO UserIsUsernameFreeDTO
  3. Query UserIsUsernameFreeQuery
  4. QueryHandler and its usages UserIsUsernameFreeQueryHandler
  5. Field definition in Prisma schema file
  6. Prisma Migration for the new field. Create with $ yarn prisma migrate dev --name users_add_email
  7. Any other usages of wording "username", "userName" and "USERNAME" (there are places on backend and frontend, but mostly single-line removals

Testing:

  • Check that command $ yarn format && yarn precommit && yarn nx affected:build succeeds
  • Check that new user can be created in app front-web (http://localhost:4200)

Related to #109 - field "email" replaces field "userName".

Router: Add basic routes

Client app:

  • /auth
  • /profile

Admin app:

  • /auth
  • /profile
  • /users # List of users
  • /users/:id # Details of a user profile

docs(README.md): improve project description for readability

Rephrase text using Amazon "backwards" approach:

  1. Heading - Name the product in a way the reader (i.e. your target customers) will understand.
  2. Sub-Heading - Describe who the market for the product is and what benefit they get. One sentence only underneath the title.
  3. Summary - Give a summary of the product and the benefit. Assume the reader will not read anything else so make this paragraph good.
  4. Problem - Describe the problem your product solves.
  5. Solution - Describe how your product elegantly solves the problem.
  6. Quote from You - A quote from a spokesperson in your company.
  7. How to Get Started - Describe how easy it is to get started.
  8. Customer Quote - Provide a quote from a hypothetical customer that describes how they experienced the benefit.
  9. Closing and Call to Action - Wrap it up and give pointers where the reader should go next.
  10. If the press release is more than a page and a half, it is probably too long.

env(back): connect CacheManager to Redis

Right now CacheManager stores values in-memory.

We should move it to Redis.

This is where it is configured.

This is how it should be configured:

import * as redisStore from 'cache-manager-redis-store'; // TODO: yarn add cache-manager-redis-store

const cacheModule = CacheModule.register({
  store: redisStore as unknown as CacheStoreFactory,
  port: 6379,
  host: API_CONFIG.redisHost,
  ttl: CacheTTL.week,
});

feat(back): add logger decorator

Right now LogService usage is a nasty overwhelming boilerplate.

Every controller's endpoint and command/query/event handler function look like this:

async methodName(...params): ReturnType {
    return this.logger.trackSegment(this.methodName.name, async () => {
      ... actual code ...
    }, {params});
  }

It would be neat to simplify this to just:

@Logger()
async methodName(...params): ReturnType {
      ... actual code ...
}

feat(front,back): add field "email"

Field properties:

Related to #108 - field "email" replaces field "userName".

Parts are similar to "userName" (check related issue) - frontend, backend, prisma field definition, prisma migration.

feat(front-shared-auth): edit user data in ProfileComponent

Features:

  • Edit fields
    • firstName
    • lastName
    • photoURL
  • Delete account

Steps:

  1. Add form with first name, last name and photoURL (just text for now) fields to In shared component libs/front/shared/auth/ui/src/lib/profile/profile.component.html.

Look at libs/front/web/auth/src/lib/create-profile/create-profile.component.html as an example.

Note: you'll need to define a form = new FormGroup({...}); in TS file to make HTML form fields work.

  1. Define @Output() update = new EventEmitter<User>(); and @Input() isSaving = false for delegating a parent component (libs/front/web/profile/src/lib/profile/profile.component.html) to handle the logic and provide a loading state back to this component.

  2. Implement necessary NGRX actions, effects, and selectors to handle the REST API interaction. Folder: libs/front/shared/auth/state/src/lib/+state

  3. Use implemented action and selector in libs/front/web/profile/src/lib/profile/profile.component.ts to initiate an update and watch the loading state. Check if it works. Repeat in libs/front/admin/profile/src/lib/profile/profile.component.html

The final result will look similar to the "Create Profile" component, just with photoURL field instead of email:

Screen Shot 2022-11-16 at 21 53 56

Auth: Remake flow

Main Flow:
1. Ask email
2. Get providers for the email (fetchSignInMethodsForEmail)
3. If no providers - show "Sign up flow" (see below)
4. If one provider - initiate it straight away
5. If multiple providers - show icons for each of them
6. User initiates some provider flow

Sign up flow:
1. Show all possible providers
2. User initiates some provider flow

Add doc for project initialization

This document is WIP. It will be used to create a script that initializes the whole Google Cloud structure for you automatically.
Project initialization (for new users)

MANUALLY:
    # Install Google Cloud CLI https://cloud.google.com/sdk/docs/install

    # Create Firebase Hosting Sites for Admin Panel & Web Client
    firebase hosting:sites:create SITE_ID
SCRIPT:

    # Environment variables:
    PROJECT_ID=FILL_WITH_YOUR_VALUE

    PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')
    CLOUD_RUN_API_APP_NAME=api
    REGION=us-central1
    FRONT_WEB_CLIENT_HOSTING_TARGET=seed-web-client
    FRONT_ADMIN_PANEL_HOSTING_TARGET=seed-admin-panel

    # Create SQL instance and get connection name
    TODO
    INSTANCE_CONNECTION_NAME=TODO
    DB_CONNECTION_STRING=TODO
    gcloud sql instances create $CLOUD_SQL_INSTANCE_NAME \
    --database-version=POSTGRES_13 \
    --region=$REGION \
    --tier=db-f1-micro \
    --authorized-networks=<AUTHORIZED_IP> \
    --root-password=DB_PASSWORD
    # outputs DB IP address


    # Enable APIs
    gcloud services enable --project "${PROJECT_ID}" \
      containerregistry.googleapis.com \
      run.googleapis.com \
      secretmanager.googleapis.com \
      firebase.googleapis.com

    gcloud config set run/platform managed
    gcloud config set run/region $REGION

    API_URL=gcloud run services describe $CLOUD_RUN_API_APP_NAME --format='value(status.url)'

    # Configure Docker to have access to Google Cloud Container Registry
    gcloud auth configure-docker


    # Grant Cloud Build permission to manage Cloud Run
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member=serviceAccount:[email protected] \
        --role=roles/run.admin
    gcloud iam service-accounts add-iam-policy-binding \
        [email protected] \
        --member=serviceAccount:[email protected] \
        --role=roles/iam.serviceAccountUser


    # Grant Cloud Build permission to deploy Firebase
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member=serviceAccount:[email protected] \
        --role=roles/firebase.admin


    # Grant Cloud Build permission to access Secret Manager
    gcloud projects add-iam-policy-binding $PROJECT_ID \
        --member=serviceAccount:[email protected] \
        --role=roles/secretmanager.secretAccessor

    # Install builders for caching
    gcloud builds submit --config cloud-build/init-builders.yaml --no-source
    gsutil mb gs://${PROJECT_ID}_cloudbuild_cache
    # TODO: add bucket lifecycle rule

    # Deploy custom builder
    docker build . -t gcr.io/$PROJECT_ID/builder -f cloud-build/builder.dockerfile
    docker push gcr.io/$PROJECT_ID/builder

    # Fill Secrets
    echo -n $REGION | \
        gcloud secrets create REGION --data-file=-

    echo -n $CLOUD_RUN_API_APP_NAME | \
        gcloud secrets create CLOUD_RUN_API_APP_NAME --data-file=-

    echo -n $API_URL | \
        gcloud secrets create API_URL --data-file=-

    echo -n "postgresql://postgres:uL9xjQk6VzWnd4vVNXwiHVe6rv4ALJ@localhost/postgres?host=/cloudsql/seed-anton:us-central1:seed-db" | \
        gcloud secrets create DB_CONNECTION_STRING --data-file=-

    echo -n "seed-anton:us-central1:seed-db" | \
        gcloud secrets create INSTANCE_CONNECTION_NAME --data-file=-

    echo -n $FRONT_WEB_CLIENT_HOSTING_TARGET | \
        gcloud secrets create FRONT_WEB_CLIENT_HOSTING_TARGET --data-file=-

    echo -n $FRONT_ADMIN_PANEL_HOSTING_TARGET | \
        gcloud secrets create FRONT_ADMIN_PANEL_HOSTING_TARGET --data-file=-


    # TODO: generate .envs/* files

OPTIONAL:
    - How to init Nx Cloud accessToken private key

Fix images in README.md

Images of Angular and Prisma are missing (broken link probably).
Please find alternative URLs and replace them.

Screen Shot 2022-11-16 at 21 10 19

env(terraform): start using Terraform to initialize cloud infrastructure

Idea

A Seed user (developer) should be able to clone Seed and run a script/command that would setup the whole infrastructure for it in the cloud.

Scope

  • Google Cloud only (for now)
  • May or may not deploy apps after the setup (just run $ yarn nx run-many --target=deploy --all=true) - should be defined if it is convenient.

Implementation options

User executes $ yarn setup:cloud that runs one of:

  • Terraform
  • Custom script (sh?) docs/how-to-init-cloud-infrastructure.md

Ideas for the future:

  • $ npx seed-startup Wizard that: 1. clones repo 2. installs deps 3. asks for ProjectID and if it should setup infrastructure now

Useful links:

List of what to be configured

Backend:

  • Cloud Run
  • PostgreSQL
  • PGBouncer
  • Redis

Frontend:

  • Firebase Hosting

Both:

  • Firebase Authentication
  • Firebase Cloud Storage
  • Environment variables

env(back-api): choose event bus solution

Responsibilities of "event bus":

  1. "Queue"
    A node posts an event, then a free node can grab and process it.
    Example: Delivery order statuses change: Order created -> Cooking -> Delivery in progress -> Delivered.

  2. "Bus"
    A node posts an event, then all nodes are notified.
    Example: WebSocket notifications to all participants in a chat app.

Candidates:

  • PostgreSQL
  • Redis
  • RabbitMQ and similar solutions
  • Google Cloud Tasks? (better avoid vendor-locking)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.