Coder Social home page Coder Social logo

tacone / loki Goto Github PK

View Code? Open in Web Editor NEW
10.0 4.0 0.0 3.82 MB

A docker / react / svelte / graphql / postgraphile starter app

Shell 14.37% Dockerfile 6.99% JavaScript 49.17% SCSS 2.80% HTML 0.37% Svelte 12.67% PLpgSQL 13.64%
postgraphile graphql-backend frontend brotli

loki's Introduction

Loki

A simple Docker / Frontend / Backend starter app, with a meaningless name.

  • ๐Ÿ‘ No-config first run
  • ๐Ÿ‘ Development mode with hot reloading everywhere
  • ๐Ÿ‘ Production mode with optional static file compilation
  • ๐Ÿ‘ Two alternative frontends: Svelte and NextJS
  • ๐Ÿ‘ GraphQL backend with Postgraphile + Migrations
  • ๐Ÿ‘ Unpriviledged user + readonly filesystem
  • ๐Ÿ‘ Small images + fast build

Installation

Clone the project, then run:

scripts/dev up

When everything is up (it will take some time for the first run) these ports will be exposed on your localhost:

  • frontend: 7000
  • svelte frontend: 7002
  • backend: 7011
  • postgres: 7040

To connect with postgres use:

  • user: postgres
  • password: postgrespassword
  • host: localhost
  • port: 7040

The scripts/dev script wraps docker-compose so you can use it in the same way (i.e. scripts/dev build, scripts/dev down, scripts/dev ps).

There is an additional command, scripts/dev ports that shows the configured ports.

The database files will be written in data/, so you can start from scratch by deleting data/ along with frontend/node_modules and backend/node_modules.

Production environment

To run the production environment, write:

scripts/production --build up

You should then access the frontend using https://localhost:7443.

Heads up!

You should always build when switching from dev to production mode.

Also, since the application building process runs while building the docker container, you need to build the containers to have the latest changes applied.

Summing up, when you start the production environment, build.

The production environment features:

  • a container with Nginx webserver, exposing HTTP (7080) and HTTPS (7443) ports. HTTP/2 enabled. Capable of gzip and brotli compression.
  • the postgres DB does not expose a public port while using the production envinroment.
  • the GraphQL backend, will not expose the development console.
  • the frontend is exported to a static website. All the files are pre-compressed with brotli during build. All timestamped files have far future expiration headers to allow proxy caching.

Please note that, at this time, frontend and backend still keep publishing their own ports (7000, 7011).

Stack

The stack consists of a few docker containers.

Frontend:

  • Nginx
  • Node
  • NextJS / Svelte Kit
  • React / Svelte
  • Alpine Linux

Backend:

  • Node
  • Postgraphile

Database:

  • Postgres
  • Alpine Linux

Frontend

The frontend is build in React + NextJS in order to make it easy to generate a static website. The forms use Final Forms. All the communication with the backend is done using GraphQL.

Svelte

An alternative frontend with Svelte + SvelteKit. Page payload ridiculously small. The forms use Felte. All the communication with the backend in done using GraphQL.

Backend

We use Postgraphile for the backend. Take a look at the documentation.

Postgraphile automatically generates the GraphQL schema for us by looking at the db schema.

The port 7011 exposes a GraphQL Console.

Database migrations: in development mode, they are automatically run only the first time. In production mode, migrations are always run at start up.

Database

The good old postgres.

Security

While security is not the focus of this starter app, by default we mount the root filesystem as readonly and run the containers with an unprivileged user.

Filesystem Layout

Folder
config/ use this directory to store your configs
data/ the db data, and npm cache is saved here
docker/ the docker-compose files for the various containers
frontend/ the frontend application code
svelte/ alternative frontend based on Svelte Kit
backend/ the backend application code
scripts/ the starting scripts (dev) and everything needed to make it work

Roadmap

Not a real roadmap, just a list of missing features I'd like to add.

Backend

  • use PM2 or any other tool to make use of all the CPU's.
  • proper auth with custom aud
  • find out how to handle uploads

Frontend/Svelte

  • image and static assets handling
  • use urql to fetch from graphql
  • persisted queries and typescript types

Nginx

  • read-only fs
  • templating / docker-gen / env vars in the confs

Caveats

  1. While Postgraphile is incredibly cool, it may not be your piece of cake. Take a look to the typeorm branch to see how implement something more traditional (then do yourself a favor and use Prism instead).

  2. While the GraphQL server validates pretty much everything, the email validation is currently performed on the client, while it would be better to also validate the mail on the server as well.

  3. If you specify a custom USER_ID in development mode, you may have issues with next (see #1)

loki's People

Contributors

tacone avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

loki's Issues

Please don't allow null lists

Null lists may break the code when it expects an array.

Take for example:

CREATE OR REPLACE VIEW public.submissions_statistics_view
AS SELECT a.age,
    c.country,
    e.experience_rating,
    g.gender,
    t.total_submissions
   FROM ( SELECT array_agg(age_stats.*) AS age
           FROM age_stats) a,
    ( SELECT array_agg(country_stats.*) AS country
           FROM country_stats) c,
    ( SELECT array_agg(experience_rating_stats.*) AS experience_rating
           FROM experience_rating_stats) e,
    ( SELECT array_agg(gender_stats.*) AS gender
           FROM gender_stats) g,
    ( SELECT count(*)::integer AS total_submissions
           FROM submissions) t;

And this query:

query MyQuery {
  submissionsStatistics {
    age {
      count
      ratio
      value
    }
    totalSubmissions
  }
}

The result with be this:

{
  "data": {
    "submissionsStatistics": {
      "age": null,
      "totalSubmissions": 0
    }
  }
}

Rather than this:

{
  "data": {
    "submissionsStatistics": {
      "age": [],
      "totalSubmissions": 0
    }
  }
}

Running the query in a Sql IDE does return the expected result though:

image

For this reason I'm going opinionated on this and just return [] wherever I find a null list, even if it's nullable.

NextJs/Webpack doesn't work if source file owner is different than process owner

NextJs fails to properly import files with a owner different than current user, even if the files have the appropriate permissions.

This only concerns development mode, because in production we are building as root.

This only concerns those who try to run the dev mode with a user with a UID different than theirs. By default we use the same UID of the current user so everything runs smooth in the default configuration.

Running the website in dev mode will result in a weird error, trying to log into the container and running the build will reveal the imports are not really working.

Svelte seems unaffected by the issue (perhaps because it uses Vite?)

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.