INSIDE

NOTES

@xf3l1x
f3l1x.io
15.03.2023

 

Tickets

Design system

UX & UI

WEB

sledovanitv.cz

Project

file

structure

.
├── .ci
├── .docker
├── app
├── assets
├── bin
├── config
├── db
├── tests
└── www
.
├── .gitignore
├── .dockerignore
├── .editorconfig
├── .env
├── .env.dist
├── .gitlab-ci.yml
├── README.md
├── Makefile
├── app.nomad
├── composer.json
├── composer.lock
├── docker-compose.yml
├── ruleset.xml
├── phpunit.xml
└── phpstan.neon
.
├── .ci
├── .docker
├── app
├── assets
├── bin
├── config
├── db
├── tests
└── www
.
├── .gitignore
├── .dockerignore
├── .editorconfig
├── .env
├── .env.dist
├── .gitlab-ci.yml
├── README.md
├── Makefile
├── app.nomad
├── composer.json
├── composer.lock
├── docker-compose.yml
├── ruleset.xml
├── phpunit.xml
└── phpstan.neon
.
├── ...
├── ...
├── src
├── ...
├── ...
├── ...
├── ...
├── ...
└── public
convention
over
configuration
➜ make
Usage:
  make <target>

Targets:
  clean                Clear project folders
  cs                   Run PHP codesniffer
  csf                  Run PHP codefixer
  deploy               Deploy application to Nomad Cluster
  dev                  Run PHP development server for API
  docker-up            Run docker stack
  docker-mac-up        Run docker stack for OSX
  docker-down          Stop docker stack
  docker-in            Enter docker container
  docker-build-app     Build docker image
  docker-push-app      Push docker image to registry
  init                 Init project for the first time
  install              Install all dependencies
  lint                 Run PHP linter
  phpstan              Run PHP phpstan
  setup                Setup project (e.q. folders, permissions)
  test                 Run PHP phpunit tests

Assets

module.exports = {
  prefix: 'tw-',
}
<div class="tailwind" x-show="open" x-cloak>
  <div class="tw-relative tw-z-[2000]">
    {* overlay *}
    <div class="tw-fixed tw-inset-0 tw-bg-black/25 tw-backdrop-blur tw-z-10 "></div>

    {* scroll container *}
    <div x-data x-init="$nextTick(() => $el.scrollTop = 0)" class="tw-fixed tw-flex tw-inset-0 tw-overflow-y-auto tw-isolate tw-z-20">
      <div @click.outside="$dispatch('modal-close')" @keyup.escape.window="$dispatch('modal-close')" class="tw-w-1/3 tw-mx-auto tw-my-auto tw-inset-0">
        <div class="tw-relative tw-font-body tw-text-white tw-bg-gray-950 tw-min-h-[calc(100vh-32px)] sm:tw-min-h-full tw-m-auto sm:tw-rounded-[20px] tw-overflow-hidden tw-shadow-lg tw-shadow-black/25">
          <div class="tw-relative"></div>
        </div>
      </div>
  </div>
</div>
tailwind.config.js
latte.latteFactory:
	setup:
		- addFunction(partial, App\Model\Latte\Partials(%appDir%/UI/@Partials)
config.neon
{define icon,
    string $icon = 'icon',
    string $file = '/img/icons/pack.svg',
    string $size = 'default',
    ...
}
    <svg n:class="$size === 'default' ? 'tw-w-6 tw-h-6' : $size, $stroke ? 'tw-stroke-current', $fill ? 'tw-fill-current', $styles">
        <use href="{base}{$file}{='#'. $icon}" />
    </svg>
{/define}
{import partial('icons')}

{include icon, "lucide:x", size => 'tw-w-7 tw-h-7', styles => 'tw-p-0.5'}
@Partials/icon.latte
default.latte
latte.latteFactory:
	setup:
		- setLoader(
			App\Model\ExtraFileLoader()::withWidgets([
				tooltip: %appDir%/UI/@Widgets/tooltip.latte
			])
		)
config.neon
<div x-data="{ open: false }" @keydown.escape="open = false" class="inline-block">
	<div class="relative flex justify-center">
		<div x-show="open" x-cloak class="absolute rounded-md text-white bg-black px-2 py-1 -mt-8 mx-auto">
			{include tooltip}
		</div>

		<div @mouseover="open = true" @mouseout="open = false" class="cursor-pointer">
			{include content}
		</div>
	</div>
</div>
{embed "~tooltip"}
	{block content}Try to move mouse over.{/block}
	{block tooltip}I am here!{/block}
{/embed}
@Widgets/tooltip.latte
default.latte
<script src="//unpkg.com/alpinejs" defer></script>
 
<div x-data="{ open: false }">
    <button @click="open = true">Expand</button>
 
    <span x-show="open">
        Content...
    </span>
</div>

Async

Framework X

Framework X

Repman

repman.io
{
    "repositories": [
        {"type": "composer", "url": "https://repo-composer.yourdomain.tld"},
        {"packagist": false}
    ]
}

Sentry

Contributte / Sentry

// Sentry
EnvironmentIntegration
ErrorListenerIntegration
ExceptionListenerIntegration
FatalErrorListenerIntegration
FrameContextifierIntegration
ModulesIntegration
RequestIntegration
TransactionIntegration
// Nette
NetteApplicationIntegration
NetteHttpIntegration
NetteSecurityIntegration
NetteSessionIntegration
ExtraIntegration

// Upload
S3UploadIntegration

// Performance
NetteApplicationMonitor
NetteDatabaseMonitor
LatteMonitor
NetteContainerMonitor
# config.neon

extensions:
    sentry: Contributte\Sentry\DI\SentryExtension
    
sentry:
    enable: %productionMode%
    client:
        dsn: "https://{KEY1}@{KEY2}.ingest.sentry.io/{KEY3}"
        sample_rate: 0.5 # 0-1 * 100

Sentry [sample rate]

Sentry [enable/disable keys]

...or business plan

Sentry [relay]

docker run --rm -it
    -v $(pwd)/config/:/srv/relay/ \
    -p 3000:3000 \
    getsentry/relay \
    run --config /srv/relay/
# /srv/relay/config.yml
relay:
    mode: proxy
    host: 0.0.0.0
    port: 3000
metrics:
    sample_rate: 0.1 # 0-1 * 100

managed

static

proxy

capture

Checkly

E2E

Terraform

terraform {
  backend "remote" {
    organization = "slicnadivcina"

    workspaces {
      name = "lasicka"
    }
  }

  required_version = ">= 1.2.1"

  required_providers {
    checkly = {
      source  = "checkly/checkly"
      version = "1.5.0-rc2"
    }
  }
}


provider "checkly" {
  api_key = var.checkly_api_key
}
resource "checkly_check" "api-time-1" {
  name                      = "API [/api/time]"
  type                      = "API"
  group_id                  = checkly_check_group.api-public-1.id
  group_order               = 1
  frequency                 = 60
  activated                 = true
  muted                     = true
  double_check              = true
  max_response_time         = 5000
  degraded_response_time    = 2000
  use_global_alert_settings = true

  locations = []

  request {
    method = "GET"
    url    = "{{ GROUP_BASE_URL }}/api/time"

    assertion {
      comparison = "EQUALS"
      property   = ""
      source     = "STATUS_CODE"
      target     = "200"
    }
  }
}

Nomad

Ansible

➜ tree
.
├── Makefile
├── README.md
├── Vagrantfile
├── defaults
│   └── main.yml
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── molecule
│   └── default
│       ├── converge.yml
│       ├── molecule.yml
│       └── verify.yml
├── provision
│   └── default.yml
└── tasks
    ├── asserts
    │   ├── main.yml
    │   └── os.yml
    └── main.yml
➜ tree
.
├── Makefile
├── README.md
├── Vagrantfile
├── defaults
│   └── main.yml
├── handlers
│   └── main.yml
├── meta
│   └── main.yml
├── molecule
│   └── default
│       ├── converge.yml
│       ├── molecule.yml
│       └── verify.yml
├── provision
│   └── default.yml
└── tasks
    ├── asserts
    │   ├── main.yml
    │   └── os.yml
    └── main.yml
➜ make

clean                 Stop and destroy Vagrant VM
install               Install dependencies using Ansible Galaxy
lint                  Run all linters
provision             Provision Vagrant VM
ssh                   Connect inside Vagrant VM
test                  Run tests using Molecule
up                    Start Vagrant VM

Versions

1.10.2

 

vs

 

2023.03.15.1825

OpenAPI

Recap

  • conventions, conventions, ....
  • docs / readme (oh yes)
  • makefile / taskfile / justfile
  • setup in 10 minutes
  • reuse technologies
  • healthchecking
  • error logging
  • tests (unit / integration / e2e)
  • hashicorp & grafana labs
  • have fun & some beer

Time to selfie 📷

Thank you!

@xf3l1x
f3l1x.io