<center>
<img alt='vivents api' src=https://i.imgur.com/BrqezHX.png width='200' />
# Vivents Backend
Vivents Backend consists of backend Node.js and terraform infrastructure repositories and components. The main part is in the `artdeal-user-api` repository. It runs on Cloud Run and uses GraphQL as a communication interface with clients.

*Vivents Backend infrastructure with all components and services*
</center>
## Project introduction π
Vivents is an app for artists, galleries and art collectors. Artists are creating art they want to sell on **vi**rtual e**vents** (vivents). We call this art simply "products". There are three types of products:
- **Artwork** - classical art like paintings, sculptures, ...
- **Luxury** - goods like watches, ...
- **NFT** - digital art signed with NFT token
These types has subtypes called categories. Each of this category contains dynamic set of attributes that can (or must) be set for each product under this category. These attributes are called "dynamic product attributes"
<center>

*Quick overview of product types, categories and dynamic product attributes*
</center>
Each artist who wants to sell his products must be confirmed as a seller (`SELLER` role). This requires going through Stripe onboarding (to have a functional payment account) and manual approval from ArtDeal organization in CMS (= administrators with role `ADMIN`). After that, the artist can create products and publish them on vivents.
Products cannot be bought before they are presented in some vivents (same as real-world galleries). Vivents are time-limited and contain a various number of pictures (static & gifs) and videos / live streams (*livestreams not ready yet*). Products and vivents can be found on users profiles, landing page or via search.
Users are also able to chat with each other. We currently support 1v1 chats and also group chats during some vivent. Users can follow each other and bookmark vivents. These operations register users as future recipients for notifications about followed user / vivent (e.g. "this vivent will start soon").
### Quick start to development π‘
The first step is to check if you have access to all services we use.
1. [Google cloud project](https://console.cloud.google.com/run/detail/europe-west1/artdeal/metrics?project=artdeal-development) (check all environmets)
2. [Firebase](https://console.firebase.google.com/u/0/project/artdeal-production/overview) (check all environments)
3. [Sentry](https://sentry.io/settings/artdeal-ag)
4. [Stripe](https://dashboard.stripe.com/)
5. [Arta](https://dashboard.arta.io/)
6. [Mux](https://dashboard.mux.com/)
7. [GetStream](https://dashboard.getstream.io/)
8. [Apollo studio](https://studio.apollographql.com/graph/Vivents)
Then try to start and setup [artdeal-userapi](https://gitlab.ack.ee/Backend/artdeal-userapi) for localhost (configurations, goproxy connection to dev and stage databases)
If you are not familiar with GraphQL principles. There is nothing better than reading the [lear section of graphql specification](https://graphql.org/learn/). It contains all practices about schema definition, pagination, caching, and such.
Read the [project vocabulary document](https://docs.google.com/document/d/1yFFDlAFDi3UsYSTfLJyo8olQ8BQHNuXlkFibgDmFCGo/edit#)
### Responsible persons π
- PM: marek.elznic@ackee.cz
- Android: david.bilik@ackee.cz
- iOS: lukas.hromadnik@ackee.cz
- Web: jiri.cermak@ackee.cz *(sharing development with client programmer)*
- BE: pavel.svagr@ackee.cz
### Merging process π§ͺ
- **Simple fixes** - typos, field renaming, one line query changes can be merged without CR, ping with some reviewer at least in the note or comment so he can review later
- Other fixes should always be reviewed at least by one person
- Do not merge features from future sprints without discussion on stand up
- If the bugfix for the feature from the previous sprint is done, *think about creating a second merge request to stage branch* (where should be the version from the previous sprint)
### Documentation π
We have no static API documentation for now. Use self-descriptive [GraphQL comments](https://dgraph.io/docs/graphql/schema/documentation/) and [deprecated](https://dgraph.io/docs/graphql/schema/deprecated/) directive for fields and operations. For examples please use [Apollo studio collection](https://studio.apollographql.com/graph/Vivents/explorer?variant=current)
### Slack channels π¬
- Shared (with clients)
- `#artdeal-app` - General discussion with clients
- `#artdeal-api` - API questions and updates shared with client developers
- `#artdeal-qa` - Channel with bug reports from clients and testers
- `#artdeal-arta` - Channel for discussions with ARTA about integration
- Internal
- `#artdeal` - General thread for everyone involved
- `#artdeal-sentry` - Sentry alerts
- `#artdeal-backend` - Channel for internal BE discussion
- `#artdeal-be-qa` - Channel for internal discussion about BE testing
- `#artdeal-ci` - Gitlab automatic notifiations from apps and backend repos
## GraphQL API π
Vivents API is built around Apollo tooling. For sharing the current state of API we use [Apollo studio](https://studio.apollographql.com/graph/Vivents/explorer?variant=current) with saved queries, changelogs, and more.
There are two GraphQL graphs accessible:
- *Client API* - No auth needed for introspection `/api`
- *Admin API* - Firebase auth required for introspection `/admin`
### Client API π±
We do not follow any predefined standard for naming of queries and operations, do zou best when thinking about the proper name. Always prefer cursor pagination over offset limit (sometimes immposible to use cursor)
### CMS API π€΄πΌ
CMS web is written in [react-admin](https://github.com/marmelab/react-admin). That means we are trying to follow as much as possible the [json-graphql-server](https://github.com/marmelab/json-graphql-server#generated-types-and-queries) schema so web developers have les work to do.
## Repositories π
### artdeal-user-api
The main backend service with two exposed GraphQL graphs for clients. Works with all third-party services and consumes webhooks for third-party services.
### artdeal-firebase-cloud-functions
Repository with Google Cloud Functions used as simple microservices. Complete list of currently used cloud functions:
- `sendNotification` - observer for Firestore - creates push notifications in case a new document is created
- `addDummyNotification` - creates a new Firestore notification document
## Components π¦Ύ
- **artdeal-tasks** - Google Cloud Tasks queue that is used to schedule a task for the API in the future. We use it mainly for time-based notifications. Since it can perform a rate-limiting, it is better to use instead of CRON jobs.
- **Resizin** - Service accessing GCS public images. Provides an API for resizing original images.
- **Firebase** - Authorization provider (social logins, email / password)
### Data storages
- **PostgreSQL** - Google cloud instance of SQL database PostgreSQL working as a base data storage
- **Redis** - Redis instance running on Google Cloud (called Memorystore) working as a secondary datastore and storage for cached data
- **Google Cloud Storage (GCS)** - Document storage for files. It is mainly used for image uploads and as a storage for invoices
- **Firestore** - Document based storage used for user notifications
### Third-party services
- **Stripe** - Payment platform
- **Arta** - Worldwide shipping service (quotes and shipping requests)
- **Mux** - API for video and live stream uploads and processing
- **GetStream** - Service for maintaining chats and messaging between users
- **Sendgrid** - Emailing service
## Environments π
### Development
- https://artdeal-zy7zn26wza-ew.a.run.app
- Reference test users
- id = 1, *ADMIN* role
- id = 2, *COLLECTOR* role
- id = 3, *SELLER* role
- Test data, mocks, all current featues and bugs
- Third party services in test mode
- Direct bearer auth possible: `Authorization: Bearer U_<user_id>`
- Dev error details
### Stage
- https://artdeal-rl7y7bnlqq-ew.a.run.app
- Pre release - Features for version release + bugfixes
- No reference users for now
- Third party services in test mode
- Direct bearer auth possible
- No dev errors
### Production
- https://artdeal-7ycdsj3y5a-ew.a.run.app
- Real data
- No direct bearer auth or dev errors
- Production ready third party services
## Release process π·
At the end of the sprint, we are releasing to stage, where we put all bugfixes till the next production release. Stage and production releases should be the same. In the slack #artdeal-backend is up-to-date list of current check-list what to before deploying. We take this list, post it into #artdeal-api slack channel and update step by step with what we are working on.
In case there is something special about your changes made during the sprint, make a reminder note for others in artdeal-backend and pin this note (great for steps 3,4 and 5). This will help others and also you to not forget anything during the release process.
**Basically the steps are following:**
1. Merge the code and resolve all conflicts
2. Check the secret values, and fill the missing keys in SecretManager (check if there are any changes in .env file)
3. Check if the third-party services need some new special setup
4. Check if there is no new CRON in the infra repository
5. Check if there is nothing new with cloud functions (do the manual deploy if needed)
6. Migrate the database & Push the new code to the target branch
In the end donβt forget to check the logs, if everything is fine.
## User Api π¨π»βπ»
### GraphQL tools
We use [Apollo tooling](https://www.apollographql.com/). We store all GraphQL fields under `graphql` folder. We distinguish between two schemas under `admin` and `client` folder with shared types in the root graphql folder. For typescript support, we use `graphql-codgen` with its configuration in `codegen.yaml`. GraphQL files are converted to Typescript files which we use for the definition of resolvers.
We have an Apollo studio organization [Vivents-api](https://studio.apollographql.com/org/vivents-api/graphs) where we store all current and up-to-date information about the new version of GraphQL schema (development environment state). This is managed by Apollo reporting - Graphql schema is automatically published to the studio with every server startup.
### Migrations
We use the newest version of `databless` with Typescript support. file. Some basic rules:
- We are using enum for table names, not for columns
- All table names and constrains with columns should be defined in `src/enums/sql.ts`
- All triggers in the current version should be stored in the `database/migrations/triggers` folder
### Error handling
GraphQL does not use HTTP status codes for error type indication. We use `extension.codes` instead. All codes should be stored in the `app/enums/errors.ts` file. The default generic error indicating a request error caused by an invalid data state or bad input is `InvalidRequestError`. To avoid boilerplate code, we are trying to separate all errors with messages in `app/components/errors.ts` file.
### Validation
Basic field validation is done directly on the schema via GraphQL scalar definitions. For advanced scalar types we use [graphql-scalars](https://www.graphql-scalars.dev/) library.
For advanced validation that requires database data and such, [GraphQL shield](https://www.graphql-shield.com/) can be used. Currently all GraphQL shield rules are in the `app/controllers/acl` folder. In case the validation process is sophisticated, it can be also done in `models` (this was the old approach).
*TODO:* We should think about introducing another GraphQL shield schema for validation or at least separate validation and ACL rules in different files.
### Quick view of project tructure
- `app`
- `controllers`
- `resolvers` - General resolver functions, mainly for transformations, defining schema resolving logic and who is responsible for which part of the schema
- `models` - Functions and operations over data models with additional validation or error handling
- `rest` - REST Api handlers (webhooks)
- `plugins` - Plugins for apollo server (similar to express middlewares)
- `acl` - GraphQL shield definitions for authorization per field or operation
- `services` - Similar to models, but logic is not bound directly to some data model *(TODO: Think about `models` structure and if it has some benefits or not)*
- `repositories` - Data models and repositories
- `utils`
- `db` - Common database functions and helpers such as `RedisCachedRepository` and others
- `generated` - Automatically generated types from `*.graphql` files (defined in `codegen.yml`)