Skip to content

Vendor Application Structure

In order for your applications to be successfully installed on Tibica, they need to be structured in a certain way. This document will guide you through the process of creating a Tibica-compatible application.

Right now we are supporting aws cdk and serverless frameworks for backend and React for frontend. If you are using a different framework, please let us know.

Folder Structure

When deploying your applications, we can deploy both frontend and backend. As of now, we сan deploy Serverless and CDK applications for backend and React applications for frontend. We require the following application structure:

source_folder
├── frontend_folder
└── backend_folder

When registering your application (see Vendor Registration Readme for more details), you can specify the names for your frontend and backend folders. For backend, please have your cdk.json (for CDK) or serverless.yml (serverless.yaml) (for Serverless) file in the root of your backend folder. For frontend, please have your package.json file in the root of your frontend folder.

Required files

Backend required files

  • pyproject.toml for Black tool
  • cdk.json and app.py (for CDK)
  • package.json and serverless.yml or serverless.yaml (for Serverless)
  • requirements.txt

Frontend required files

  • yarn.lock
  • package.json

Installation commands

In the process of installation, we run the following commands.

Backend installation commands

CDK

Terminal window
black --check .
pip3 install .
cdk synth
cdk bootstrap
cdk diff
cdk deploy

Serverless

Terminal window
black --check .
yarn cache clean
yarn
sls package
sls deploy

Frontend installation commands

Terminal window
sed -i -e "/resolved:* .*$/d" yarn.lock
yarn cache clean
yarn
yarn run build
aws s3 sync ./root_path/ s3://{WebSiteS3}/

If you need us to run any other commands to install your application, please let us know.

Frontend build specifics

We are building frontend using yarn run build command. The folder that is produced by this command should be called build (dist and other folder names are not supported as of now).

We are using AWS CloudFront to serve your build from an S3 bucket. It is important to note that due to security measures we can only serve the following file paths:

  • index.html
  • static/{filename}
  • assets/{filename}
  • ui/static/{filename}
  • ui/assets/{filename}

Environment variables

We will add environment variables required for your application to the environment automatically. Here are the list of environment variables names that you will be able to use in your application:

Backend

  • app
  • app_alias
  • layer_bucket
  • layer_object_key
  • region
  • customer_id
  • environment_id
  • environment_version
  • WebSiteS3
  • version
  • hashVersion
  • cloud_users_private_client_id
  • cloud_users_private_client_secret
  • cloud_users_private_client_scope
  • cloud_users_pool_domain
  • hosted_zone_id
  • dns_on
  • certificate_arn
  • domain_name
  • install_bucket

Frontend

  • REACT_APP_API_SOCKET
  • VITE_API_SOCKET
  • REACT_APP_API_LINK
  • VITE_API_LINK
  • PUBLIC_URL
  • VITE_PUBLIC_URL
  • REACT_APP_app
  • VITE_app
  • REACT_APP_app_alias
  • VITE_app_alias
  • REACT_APP_layer_bucket
  • VITE_layer_bucket
  • REACT_APP_layer_object_key
  • VITE_layer_object_key
  • REACT_APP_region
  • VITE_region
  • REACT_APP_customer_id
  • VITE_customer_id
  • VITE_cloud_users_cognito_arn
  • VITE_cloud_users_cognito_app_client_id
  • VITE_oauth_domain
  • VITE_cloud_users_app_name
  • VITE_cloud_users_api_url

This is not an extensive list and there may be other environment variables not listed here. If you need any other variables to be added, please contact us.

Syntax Check

We are using black to check your backend Python code for any syntax and style errors. In order for us to do it, you need to add black to your requirements.txt file and have a pyproject.toml file in your backend folder with the following content:

[tool.black]
line-length = 120
exclude = '''
(
/(
\.eggs # exclude a few common directories in the
| \.git # root of the project
| \.hg
| \.mypy_cache
| \.tox
| \.venv
| \.layers
| _build
| buck-out
| build
| dist
| node_modules
| \.cdk.out/*
| cdk.out
| venv
)/
)
'''

Policy Check

It is highly possible that you will be creating IAM policies, users and roles in your application stack. We require you to follow the principle of least privilege and only grant the permissions that are necessary for your application to function. Therefore, we prohibit the use of wildcards (*) in your policies. In order to enforce this, we are using a policy validator that will run the check. We are using AWS CloudFormation Guard to check your stack against our custom policies. You can read more about them in the CloudFormation Template Rules.md file.

Tagging Resources

You are required to tag resources according to our policies in order to allow for a smooth operation of your application. Your application CloudFormation stacks (including nested stacks) need to have the following tags:

KeyValue
tibica-applicationSERVICE_NAME
tibica-customerCUSTOMER_ID
tibica-parentSTACK_NAME

SERVICE_NAME is the name of your application starting with tibica- (for example, tibica-cloud-git). CUSTOMER_ID is the id of the customer on which your application is installed. You will get it as an environment variable in your application. STACK_NAME is the name of your stack. It consists of your SERVICE_NAME and CUSTOMER_ID split by a dash: {SERVICE_NAME}-{CUSTOMER_ID}.

Please note that we will not be able to manage applications that do not have these tags or have names that do not start with tibica-.

Any AWS resources that your application creates (including but not limited to IAM users, CloudFormation stacks, CodeCommit repositories, CodeBuild projects, etc.) need to have the following tags:

KeyValue
tibica-applicationSERVICE_NAME
tibica-customerCUSTOMER_ID
tibica-childJOINT_STACK_NAME

JOINT_STACK_NAME has to be comprised of the STACK_NAME and the name of the child resource (stack name if it’s CloudFormation) split by a @: {STACK_NAME}@{CHILD_STACK_NAME}.

Bundling layers

We can bundle your Python layers with a requirements.txt file for you and create a .zip file for you. In order for us to be able to do it, please structure your layers in the following way:

  • If you are using an x86_64, use the following structure:
source_folder
├── frontend_folder
└── backend_folder
└── layers
└── layer_name_x86_64
├── requirements.txt
└── your_package
  • If you are using an arm64, use the following structure:
source_folder
├── frontend_folder
└── backend_folder
└── layers
└── layer_name
├── requirements.txt
└── your_package
  • If needed, you can have us package both an arm and x86_64 version by defining multiple layers:
source_folder
├── frontend_folder
└── backend_folder
└── layers
├── layer_name
│ ├── requirements.txt
│ └── your_package
└── layer_name_x86_64
├── requirements.txt
└── your_package

We will download platform-specific dependencies for you and package into a .zip file with the following structure:

layer_name-app_name-customer_id-layer-timestamp.zip
└──python
├── your_package
└── other_dependencies

This will produce two environment variables that you can use in your application: layer_bucket_name and layer_object_key_layer_name for each layer created.

So if your layer name is utils_x86_64, this is how you can access the environment variables to create a layer:

import os
from aws_cdk import Stack, aws_lambda as _lambda, aws_s3 as s3, RemovalPolicy
layer_bucket_name = os.getenv("layer_bucket_name", default="layer-bucket")
layer_utils_x86 = os.getenv("layer_object_key_utils_x86_64", default="")
class CdkStack(Stack):
def __init__(self, scope, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
layer_utils = _lambda.LayerVersion(
self,
"UtilsLambdaLayer",
code=_lambda.Code.from_bucket(
bucket=s3.Bucket.from_bucket_name(self, "layer_bucket", bucket_name=layer_bucket_name),
key=layer_utils_x86,
),
compatible_runtimes=[_lambda.Runtime.PYTHON_3_8],
removal_policy=RemovalPolicy.RETAIN,
compatible_architectures=[_lambda.Architecture.X86_64],
layer_version_name="utils",
)