Giter VIP home page Giter VIP logo

flybot.sg's People

Contributors

flybot-nam-nguyenhoai avatar github-actions[bot] avatar pez avatar robertluo avatar skydread1 avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

flybot.sg's Issues

There is no user data and api

Problem

There is no User in the backend api.

Suggestion

  • Add user datomic schema
  • Add pull schema
  • Add /users to the api pullable-data
  • Add google oauth2 support
  • Add different reitit routes for the different permissions

The `head` is lacking relevant information for SEO

Problem

The Helmet component we have is quite empty and should have contain more info.

Also all pages have the same meta which is not advised when it comes to SEO.

Suggestion

  • add props to the Helmet component to have a custom title, description and keywords for each page.
  • add twitter and facebook cards for better link embedding in those popular social platforms.

Social cards generator/validator:

Generator for Google+/Facebook/Twitter:

Validator:

There is no Flybot logo

Problem

Having a logo would make the website more vivid.

Suggestion

Use one of the logo provided by the team at 4AVCT

There is no way to separately edit a page and a post

Problem

When the user (in editor mode) wants to update the page config (such as the order of post for instance), we don't want to show the individual post edit configs at the same time).

Suggestion

  • To avoid confusion in the front-end, we should have a :post/mode and a :page/mode to distinguish the page settings from the post settings.
  • We should have a Edit Page button to show/hide the page config option in editor mode as well.

There is no `About us` page

Problem

There is no page introducing Flybot company and the team

Suggestion

  • Add about me page with company description and the GitHub/LinkedIn account of the team members

There is a confusion between validation schema and pull schema

Problem

We can share the same Malli schemas for

  • frontend validation (form input)
  • backend validation (request params)
  • pull pattern

The main difference between validation schema and pull pattern schema is that pull pattern schemas have all keys optional as we do not want to force the client to require any fields.

However, for validation (form inputs for frontend, request params for backend), we often need the client to provide some mandatory fields.

Suggestion

  • Add the require fields to the validation schema
  • Use the malli.util/optional-keys function to make all the keys optional for the pattern (query) schema

There is no way to sort posts in a page

Problem

The post or by default ordered by creation date.
We cannot sort them by last edited date or specify individual post positions.
We don't have the date infos display in the UI.

Suggestion

  • Display the creation and last edition date for each post
  • Add DB schema accordingly.

All the css is contained in one React component

Problem

If though our content is relatively small, we should still export at least common parts such as the header and footer.

It is better for reusability and scaling if we need in the future.

Suggestion

Break down the page in different React components.

There is no favicon

Problem

We do not have the favicon setup on our website.

Suggestion

Use the Flybot logo as favicon

The different modes do not have the right scope

Problem

As for now in the frontend, the user, page and post mode are at the same level such as:

;; initial db
{:app/current-view (rfe/push-state :flybot/home)
 :app/theme        local-store-theme
 :user/mode        :reader
 :page/mode        :read ;;wrong scope
 :post/mode        :read ;; wrong scope
 :nav/navbar-open? false}

This is conceptually wrong as each page should have its mode and each post should have its mode.

This has for consequence some overcomplexity in the logic at the post level which could be easily avoided via individual post modes and individual page modes.

Suggestion

  • Change flat pages and posts maps to indexed maps to better represent the front-end layers.
  • Move :page/mode to page level and :post/mode to post level
  • A new post and an existing post should have the same edit component: a new post just has a temp id.
  • Obvious refactoring should result from those improvements

There is no readme content

Problem

There is no readme describing the stack used and how to add content for non-developers via the markdown files.

Suggestion

  • Add stack used and links to the libraries
  • Add instruction on how to use the dev build to test locally
  • Add instruction on how to add/update markdown and how to use the optional configs

There cannot be pattern with multiple :with option

Problem

The current implementation execute the side effect when a pattern contains a :with option in one of its keys.
This cause no problem if there is only one key using the :with option such as:

;; the value of :a being a function causing a transaction
{(list :a :with [a1]) '?}

However, if there are 2 keys with function causing transactions, the order cannot be guaranteed, such as:

;; values of :a and :b cause transactions
;; no guaranty of order
{(list :a :with [a1]) '?
 (list :b :with [b1]) '?}

There is no way to edit an existing post

Problem

As for now, we can only create a post from scratch but not modify an existing one.
Also the new post can only be added to the blog page.

Suggestion

  • Add the possibility to edit an exiting post in the UI
  • Allow to create/edit a post on any page

The server life-cycle depends on a global state

Problem

As for now, we use mount to create/populate/close the DB and start/stop the server.
Mount lets each namespace declare global variables to be added to the life-cycle via defstate.

We prefer the approach where we define a unique system map which can handle app life-cycle management while retaining the feature of a simple Clojure map.

Suggestion

Use robertluo/fun-map to manage the app life-cycle.

The viewport meta is missing in the head

Problem

The following as been removed by accident in the previous PR:

<meta name="viewport" content="width=device-width, initial-scale=1" />

So the display is not correct on mobile

Suggestion

Add the line back to index.html

There is no way to preview a post

Problem

Same as for this github issue, it is convenient to have a way to preview the post before submitting it.

Suggestion

  • Use a local atom and reagent to render on the fly the post information
  • Add a preview/edit switch button and display/edit the post

There is no way to specify a dark-mode image

Problem

As for now, we cannot choose one image for light mode and one image for dark mode while writing a post via the UI.

Suggestion

We should be able to specify:

  • the dark image source for the beside-image. (Add field to UI and DB)
  • the dark image sources for the images inside the article itself. (Create custom syntax for this use case)

There is no css purging

Problem

purge allow to deploy smaller css in production.

Suggestion

Add the purge config in tailwinbg.config,js

Request handler are not pure

Problem

As for now, we perform the http request directly in the handler (which works but is not pure).

Suggestion

  • Follow the advice from re-frame and use the library re-frame-http-fx to have clean isolated http Effects
  • Remove the ajax namespace as the request effects will be handles in reg-event-fx.

There is no content and basic layout

Problem

We just want a basic static website as our content is small.

Suggestion

  • Use Tailwind for embedded css in html classes.
  • Regarding the application form - a link to a google form sounds like the cleanest and easiest option.

There is no GitHub workflow for the build

Problem

We first though of letting netlify do the building as it supports Clojure CLI command such as aliases.

However netlify does not support clj -T of build.js which is a problem for us.

Ideally, we want to be host agnostic and not expose the js bundle in the github repo.

Suggestion

  • Create a GitHub action to build our website from the source code and deploy it to netlify directly

There is no dark mode support

Problem

Lots of people prefer dark version of website to not hurt their eyes too much especially when it's late.

Lots of people actually have their device setting defaulting to dark mode.

Suggestion

  • add the dark mode colours in the layout
  • offer the possibility to toggle on/off dark mode.

The pngs are not optimised

Problem

We did not optimise the PNG files before upload and that is not good for bandwidth consumption and overall speed of the website.

Suggestion

Using a site like tinypng to compress the images and update the repo.

Reloading a subpage causes `404`

Problem

Reloading the main page / is fine but reloading a subpage (for instance /about) causes a page not found.

Suggestion

Hosting a React application on the Netlify platform often runs into an "Error 404". This is because an app built with Reactjs is a SPA (Single Page Application). Routing is done on the application and no HTTP calls are made to fetch pages server-side.

The fix is to add a _redirects file in the public.

This tells Netlify to route all redirects to the index.html which is the root entry of our application.

There is not way to login

Problem

As for now, anybody can create a post.

Suggestion

  • Add a register/login page to the front-end
  • Add a datomic schema for the users
  • Add ajax request and front-end state events/subscriptions

There is no way to provide a ring handler to Figwheel

Problem

We can provide a ring handler in the figwheel-main.edn.

This allow us to have a server running for the backend while preserving the hot cljs reloading for front-end development.

Suggestion

  • Fix the Piggieback error introduced by datomic-free (or datomic dev-local) deps in deps.edn
  • Provide a dedicated handler for dev that setup the DB and populate it.

There is no way to pull only the relevant data from the server

Problem

We are often interested in a subset of the data returns by the server from a given request.

This is made intuitive via the library lasagna-pull.

Rational

In the client request' body, a pull pattern is provided to only pull a subset of what the server logic could have computed. The server will then perform the corresponding logic and return only the data requested by the client.

In our case, we can create a post like this:

;; front-end (.cljs)
{:http-xhrio {:method :post
              :uri          "/all"
              :params {(list :op/create-post :with [post])
                       {:post/id '?
                        :post/page '?
                        :post/css-class '?
                        :post/creation-date '?
                        :post/last-edit-date '?
                        :post/show-dates? '?
                        :post/md-content '?
                        :post/image-beside {:image/src '?
                                            :image/src-dark '?
                                            :image/alt '?}}}
              :format          (edn-request-format {:keywords? true})
              :response-format (edn-response-format {:keywords? true})
              :on-success      [:fx.http/send-post-success current-page]
              :on-failure      [:fx.http/failure]}}

You can see that the pattern allows us

  • to specify what data we are interested in
  • to provide options to perform additional logic on the data

The :with option in the key (list :op/create-post :with [post]) allows us to provide some params to the value. In our case, we provide a post to the value of the key :op/create-post which is a function.

We can use schema for data validation: the server can provide a schema with the data allowed to be pulled by the client. We can have different schemas for different requests. The schemas could even be used for front-end validation as well so we can put them in a .cljc file such as:

;; front/back end validation (.cljc)
(def post-schema
  [:map {:closed true}
   [:post/id :string]
   [:post/page :keyword]
   [:post/css-class {:optional true} :string]
   [:post/creation-date inst?]
   [:post/last-edit-date {:optional true} inst?]
   [:post/show-dates? {:optional true} :boolean]
   [:post/md-content :string]
   [:post/image-beside
    {:optional true}
    [:map
     [:image/src :string]
     [:image/src-dark :string]
     [:image/alt :string]]]])

(def ops-schema
  "Schema of all the operations that can be performed in the server."
  [:map
   [:op/create-post {:optional true} post-schema]
   ...])

On the server-side, we have the run/pull function accepting the pattern, a malli schema and the data to pull the info from.
The pattern comes from the request, the schema is defined by the server (can be viewed as a protocol to be respected by the client) and the data is what results from the backend logic (after eventual side effect):

;; backend (.clj)
(defn ops-fn
  [sys]
  {:op/create-post   (fn [params] (:response (create-post (assoc sys :params params))))
   ...})

;; call to the pull function in the request handler
(first (pull/run body-params v/ops-schema (op/ops-fn sys)))

In our example, the post provided in the pattern for the key :op/create-post is given to the create-post function which will update the db and send a response respecting the post-schema shown above.

An example of what could be returned by the server is:

{:op/create-post #:post{:id "2bbf635f-1210-4168-9b8a-6f668461ccbe"
                        :page :home
                        :css-class "magic"
                        :creation-date #inst "2022-10-10T03:59:24.492-00:00"
                        :md-content "some md content"
                        :image-beside
                        #:image{:src "assets/binary.svg",
                                :src-dark "assets/binary-dark-mode.svg"
                                :alt "Love word written in base 2"}}}

Note that, in opposition to a RESP api, the request type does not matter as we just care about the pattern provided in the body. Same remark for the routes, we do not care as the end-point is implicitly defined in the data shape itself.

The post form still uses an atom and no error handling

Problem

As we opt for re-frame, we should avoid local atom and use dispatch/subscribe instead.

Also, there is no way to know if an error occurred and if it is a validation error or a request error.

Suggestion

  • Use re-frame framework for the post creation form.
  • Add a proper way to dispatch errors.

There is no custom domain

Problem

As for now, our webstie domain is the default random name assigned by Netlify.

However, we already own our domain flybot.sg via godaddy

Suggestion

Use the instruction provided here to add our custom domain to Netlify.

The website has not been deployed

Problem

Now that we have a good basic content/layout, we can deploy the website to a free tier of a server host.

Our website is very small and won't generate heavy traffic at all hence the free tier should suffice.

Suggestion

Netlify is good candidate for hosting for the following reasons:

  • has free tier
  • can be used for commercial use technically (unlike the new trendy host Vercel)
  • works with node and so react
  • can build from Github and setup continuous integration
  • easy to setup

Dark mode is used by default instead of localstorage

Problem

The localstorage value is not retrieve properly hence defaulting to dark mode.

Suggestion

in flybot.lib.cljs.localstorage

Replace

(if-let [l-storage-theme (keyword (get-item "theme"))]
...)

by

(if-let [l-storage-theme (get-item (keyword "theme"))]
...)

The handler request params expect an operation which is not the idea of pull

Problem

As for now, the client request is expected to have op-name, op-params and pattern such as:

{:op-name   :op/add-page
 :op-params [page]
 :pattern   '{:page/name ?}}

This protocol restricts the implementation and do not make full use of the pull stack.

Suggestion

We should use the pull-pattern :with option in the request and only pass a pattern to the server.

The example above could become:

{(list :something :with [page])
    {:page/name '?}}

The :something needs to be related to actual data and not a server operation

It is backend responsibility to ensure the params given with with to the value of :something are allowing us to compute the corresponding logic and to describe side effects to be executed as well.

Suggestion

Just use a pattern as request params and modify the backend to get rid of the operations workflow.

There is no way to write a post and store it

Problem

There is no way to write a post in the front-end ad store it in the backend.

Suggestion

  • Add a create-post page with a form to write the markdown and some properties.
  • Use cljs-ajax to send the post-request to the backend
  • Use malli schema for data validation

There is no backend api tests

Problem

We do not have tests for the reitit ring-handler.

Suggestion

  • Use a fun-map test-system to setup a test server and test db with sample data
  • Tests the different routes of the pulled-data via the different pull-patterns

Dark mode sis not enabled by default

Problem

dark mode should be the default theme if localStorage is empty

Suggestion

Add the dark mode theme with dark value in the localStorage.

There is no backend for data persistence

Problem

In theory, a SPA is fine for our need as we just deliver static content.

However, as part of our work on our open-source lasagna stack (fun-map, pull and remote-pull),
we want to use our website as an example of the good use case of our stack.

So, for a pull api and map value accessing demo to make sense, we need an actual backend.

Suggestion

  • backend in Clojure
  • Use aleph/ring for http
  • Use xtdb as datalog DB

There is no simple data storage in the backend

Problem

We need to be able to store the data in a DB.

Suggestion

  • Use datomic-free library with a in-memory DB

Note

In the future, we will need actual data persistence but at this stage, we are just experimenting in the dev environment.

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.