diff --git a/.gitignore b/.gitignore index 4d318a8..6f92a01 100644 --- a/.gitignore +++ b/.gitignore @@ -116,8 +116,3 @@ dist .yarn/install-state.gz .pnp.* -static/ - -.idea - -elm-stuff/ diff --git a/todo/LICENSE b/LICENSE similarity index 100% rename from todo/LICENSE rename to LICENSE diff --git a/todo/README.md b/README.md similarity index 100% rename from todo/README.md rename to README.md diff --git a/todo/config.json b/config.json similarity index 50% rename from todo/config.json rename to config.json index 948073a..87abf0b 100644 --- a/todo/config.json +++ b/config.json @@ -3,7 +3,5 @@ "https": false, "alter_db": true, "port": 8080, - "db_url": "postgres://postgres:@127.0.0.1/todo", - "cert": "", - "cert_key": "" + "db_url": "postgres://postgres:@127.0.0.1/todo" } \ No newline at end of file diff --git a/elm-deprecated/elm.json b/elm-deprecated/elm.json deleted file mode 100644 index 01ba003..0000000 --- a/elm-deprecated/elm.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "type": "application", - "source-directories": [ - "src" - ], - "elm-version": "0.19.1", - "dependencies": { - "direct": { - "elm/browser": "1.0.2", - "elm/core": "1.0.5", - "elm/html": "1.0.0", - "elm/http": "2.0.0", - "elm/json": "1.1.3", - "elm/time": "1.0.0", - "elm/url": "1.0.0", - "f0i/iso8601": "1.1.2", - "mdgriffith/elm-ui": "1.1.8" - }, - "indirect": { - "elm/bytes": "1.0.8", - "elm/file": "1.0.5", - "elm/virtual-dom": "1.0.2" - } - }, - "test-dependencies": { - "direct": {}, - "indirect": {} - } -} diff --git a/elm-deprecated/index.html b/elm-deprecated/index.html deleted file mode 100644 index 6c718e8..0000000 --- a/elm-deprecated/index.html +++ /dev/null @@ -1,14025 +0,0 @@ - - - - - Main - - - - - -

-
-
-
-
-
\ No newline at end of file
diff --git a/elm-deprecated/src/About.elm b/elm-deprecated/src/About.elm
deleted file mode 100644
index b65252d..0000000
--- a/elm-deprecated/src/About.elm
+++ /dev/null
@@ -1,9 +0,0 @@
-module About exposing (..)
-
-import Element exposing (..)
-import Model exposing (..)
-
-
-getPage : Model -> Element Msg
-getPage _ =
-    text "About page."
diff --git a/elm-deprecated/src/Account.elm b/elm-deprecated/src/Account.elm
deleted file mode 100644
index 35a5d69..0000000
--- a/elm-deprecated/src/Account.elm
+++ /dev/null
@@ -1,9 +0,0 @@
-module Account exposing (..)
-
-import Element exposing (..)
-import Model exposing (..)
-
-
-getPage : Model -> Element Msg
-getPage _ =
-    text "Account page."
diff --git a/elm-deprecated/src/Api.elm b/elm-deprecated/src/Api.elm
deleted file mode 100644
index acdbec6..0000000
--- a/elm-deprecated/src/Api.elm
+++ /dev/null
@@ -1,290 +0,0 @@
-port module Api exposing (Cred, addServerError, application, decodeErrors, delete, get, login, logout, post, put, register, settings, storeCredWith, username, viewerChanges)
-
-{-| This module is responsible for communicating to the Conduit API.
-It exposes an opaque Endpoint type which is guaranteed to point to the correct URL.
--}
-
-import Api.Endpoint as Endpoint exposing (Endpoint)
-import Avatar exposing (Avatar)
-import Browser
-import Browser.Navigation as Nav
-import Http exposing (Body, Expect)
-import Json.Decode as Decode exposing (Decoder, Value, decodeString, field, string)
-import Json.Encode as Encode
-import Url exposing (Url)
-import Username exposing (Username)
-
-
-
--- CRED
-
-
-{-| The authentication credentials for the Viewer (that is, the currently logged-in user.)
-This includes:
-
-  - The cred's Username
-  - The cred's authentication token
-    By design, there is no way to access the token directly as a String.
-    It can be encoded for persistence, and it can be added to a header
-    to a HttpBuilder for a request, but that's it.
-    This token should never be rendered to the end user, and with this API, it
-    can't be!
-
--}
-type Cred
-    = Cred Username String
-
-
-username : Cred -> Username
-username (Cred val _) =
-    val
-
-
-credHeader : Cred -> Http.Header
-credHeader (Cred _ str) =
-    Http.header "authorization" ("Token " ++ str)
-
-
-{-| It's important that this is never exposed!
-We expose `login` and `application` instead, so we can be certain that if anyone
-ever has access to a `Cred` value, it came from either the login API endpoint
-or was passed in via flags.
--}
-credDecoder : Decoder Cred
-credDecoder =
-    Decode.succeed Cred
-        |> field "username" Username.decoder
-        |> field "token" Decode.string
-
-
-
--- PERSISTENCE
-
-
-decode : Decoder (Cred -> viewer) -> Value -> Result Decode.Error viewer
-decode decoder value =
-    -- It's stored in localStorage as a JSON String;
-    -- first decode the Value as a String, then
-    -- decode that String as JSON.
-    Decode.decodeValue Decode.string value
-        |> Result.andThen (\str -> Decode.decodeString (Decode.field "user" (decoderFromCred decoder)) str)
-
-
-port onStoreChange : (Value -> msg) -> Sub msg
-
-
-viewerChanges : (Maybe viewer -> msg) -> Decoder (Cred -> viewer) -> Sub msg
-viewerChanges toMsg decoder =
-    onStoreChange (\value -> toMsg (decodeFromChange decoder value))
-
-
-decodeFromChange : Decoder (Cred -> viewer) -> Value -> Maybe viewer
-decodeFromChange viewerDecoder val =
-    -- It's stored in localStorage as a JSON String;
-    -- first decode the Value as a String, then
-    -- decode that String as JSON.
-    Decode.decodeValue (storageDecoder viewerDecoder) val
-        |> Result.toMaybe
-
-
-storeCredWith : Cred -> Avatar -> Cmd msg
-storeCredWith (Cred uname token) avatar =
-    let
-        json =
-            Encode.object
-                [ ( "user"
-                  , Encode.object
-                        [ ( "username", Username.encode uname )
-                        , ( "token", Encode.string token )
-                        , ( "image", Avatar.encode avatar )
-                        ]
-                  )
-                ]
-    in
-    storeCache (Just json)
-
-
-logout : Cmd msg
-logout =
-    storeCache Nothing
-
-
-port storeCache : Maybe Value -> Cmd msg
-
-
-
--- SERIALIZATION
--- APPLICATION
-
-
-application :
-    Decoder (Cred -> viewer)
-    ->
-        { init : Maybe viewer -> Url -> Nav.Key -> ( model, Cmd msg )
-        , onUrlChange : Url -> msg
-        , onUrlRequest : Browser.UrlRequest -> msg
-        , subscriptions : model -> Sub msg
-        , update : msg -> model -> ( model, Cmd msg )
-        , view : model -> Browser.Document msg
-        }
-    -> Program Value model msg
-application viewerDecoder config =
-    let
-        init flags url navKey =
-            let
-                maybeViewer =
-                    Decode.decodeValue Decode.string flags
-                        |> Result.andThen (Decode.decodeString (storageDecoder viewerDecoder))
-                        |> Result.toMaybe
-            in
-            config.init maybeViewer url navKey
-    in
-    Browser.application
-        { init = init
-        , onUrlChange = config.onUrlChange
-        , onUrlRequest = config.onUrlRequest
-        , subscriptions = config.subscriptions
-        , update = config.update
-        , view = config.view
-        }
-
-
-storageDecoder : Decoder (Cred -> viewer) -> Decoder viewer
-storageDecoder viewerDecoder =
-    Decode.field "user" (decoderFromCred viewerDecoder)
-
-
-
--- HTTP
-
-
-get : Endpoint -> Maybe Cred -> Decoder a -> Cmd a
-get url maybeCred decoder =
-    Endpoint.request
-        { method = "GET"
-        , url = url
-        , expect = Http.expectJson decoder
-        , headers =
-            case maybeCred of
-                Just cred ->
-                    [ credHeader cred ]
-
-                Nothing ->
-                    []
-        , body = Http.emptyBody
-        , timeout = Nothing
-        , withCredentials = False
-        }
-
-
-put : Endpoint -> Cred -> Body -> Decoder a -> Cmd a
-put url cred body decoder =
-    Endpoint.request
-        { method = "PUT"
-        , url = url
-        , expect = Http.expectJson decoder
-        , headers = [ credHeader cred ]
-        , body = body
-        , timeout = Nothing
-        , withCredentials = False
-        }
-
-
-post : Endpoint -> Maybe Cred -> Body -> Decoder a -> Cmd a
-post url maybeCred body decoder =
-    Endpoint.request
-        { method = "POST"
-        , url = url
-        , expect = Http.expectJson decoder
-        , headers =
-            case maybeCred of
-                Just cred ->
-                    [ credHeader cred ]
-
-                Nothing ->
-                    []
-        , body = body
-        , timeout = Nothing
-        , withCredentials = False
-        }
-
-
-delete : Endpoint -> Cred -> Body -> Decoder a -> Cmd a
-delete url cred body decoder =
-    Endpoint.request
-        { method = "DELETE"
-        , url = url
-        , expect = Http.expectJson decoder
-        , headers = [ credHeader cred ]
-        , body = body
-        , timeout = Nothing
-        , withCredentials = False
-        }
-
-
-login : Http.Body -> Decoder (Cred -> a) -> Cmd a
-login body decoder =
-    post Endpoint.login Nothing body (Decode.field "user" (decoderFromCred decoder))
-
-
-register : Http.Body -> Decoder (Cred -> a) -> Cmd a
-register body decoder =
-    post Endpoint.users Nothing body (Decode.field "user" (decoderFromCred decoder))
-
-
-settings : Cred -> Http.Body -> Decoder (Cred -> a) -> Cmd a
-settings cred body decoder =
-    put Endpoint.user cred body (Decode.field "user" (decoderFromCred decoder))
-
-
-decoderFromCred : Decoder (Cred -> a) -> Decoder a
-decoderFromCred decoder =
-    Decode.map2 (\fromCred cred -> fromCred cred)
-        decoder
-        credDecoder
-
-
-
--- ERRORS
-
-
-addServerError : List String -> List String
-addServerError list =
-    "Server error" :: list
-
-
-{-| Many API endpoints include an "errors" field in their BadStatus responses.
--}
-decodeErrors : Http.Error -> List String
-decodeErrors error =
-    case error of
-        Http.BadStatus errid ->
-            [ Int.toString errid ]
-
-        err ->
-            [ "Server error" ]
-
-
-errorsDecoder : Decoder (List String)
-errorsDecoder =
-    Decode.keyValuePairs (Decode.list Decode.string)
-        |> Decode.map (List.concatMap fromPair)
-
-
-fromPair : ( String, List String ) -> List String
-fromPair ( field, errors ) =
-    List.map (\error -> field ++ " " ++ error) errors
-
-
-
--- LOCALSTORAGE KEYS
-
-
-cacheStorageKey : String
-cacheStorageKey =
-    "cache"
-
-
-credStorageKey : String
-credStorageKey =
-    "cred"
diff --git a/elm-deprecated/src/Api/Endpoint.elm b/elm-deprecated/src/Api/Endpoint.elm
deleted file mode 100644
index f4a4f05..0000000
--- a/elm-deprecated/src/Api/Endpoint.elm
+++ /dev/null
@@ -1,99 +0,0 @@
-module Api.Endpoint exposing (Endpoint, login, request, tags, todo, todoList, user, users)
-
-import Http
-import Todo.UUID as UUID exposing (UUID)
-import Url.Builder exposing (QueryParameter)
-import Username exposing (Username)
-
-
-{-| Http.request, except it takes an Endpoint instead of a Url.
--}
-request :
-    { body : Http.Body
-    , expect : Http.Expect a
-    , headers : List Http.Header
-    , method : String
-    , timeout : Maybe Float
-    , url : Endpoint
-    , tracker : Maybe String
-    }
-    -> Cmd a
-request config =
-    Http.request
-        { body = config.body
-        , expect = config.expect
-        , headers = config.headers
-        , method = config.method
-        , timeout = config.timeout
-        , url = unwrap config.url
-        , tracker = config.tracker
-        }
-
-
-
--- TYPES
-
-
-{-| Get a URL to the Conduit API.
-This is not publicly exposed, because we want to make sure the only way to get one of these URLs is from this module.
--}
-type Endpoint
-    = Endpoint String
-
-
-unwrap : Endpoint -> String
-unwrap (Endpoint str) =
-    str
-
-
-url : List String -> List QueryParameter -> Endpoint
-url paths queryParams =
-    -- NOTE: Url.Builder takes care of percent-encoding special URL characters.
-    -- See https://package.elm-lang.org/packages/elm/url/latest/Url#percentEncode
-    Url.Builder.crossOrigin "https://conduit.productionready.io"
-        ("api" :: paths)
-        queryParams
-        |> Endpoint
-
-
-
--- ENDPOINTS
-
-
-login : Endpoint
-login =
-    url [ "users", "login" ] []
-
-
-user : Endpoint
-user =
-    url [ "user" ] []
-
-
-users : Endpoint
-users =
-    url [ "users" ] []
-
-
-follow : Username -> Endpoint
-follow uname =
-    url [ "profiles", Username.toString uname, "follow" ] []
-
-
-
--- ARTICLE ENDPOINTS
-
-
-todo : UUID -> Endpoint
-todo uuid =
-    url [ "articles", UUID.toString uuid ] []
-
-
-todoList : List QueryParameter -> Endpoint
-todoList params =
-    url [ "articles" ] params
-
-
-tags : Endpoint
-tags =
-    url [ "tags" ] []
diff --git a/elm-deprecated/src/Asset.elm b/elm-deprecated/src/Asset.elm
deleted file mode 100644
index daa023b..0000000
--- a/elm-deprecated/src/Asset.elm
+++ /dev/null
@@ -1,46 +0,0 @@
-module Asset exposing (Image, defaultAvatar, error, loading, src)
-
-{-| Assets, such as images, videos, and audio. (We only have images for now.)
-We should never expose asset URLs directly; this module should be in charge of
-all of them. One source of truth!
--}
-
-import Html exposing (Attribute, Html)
-import Html.Attributes as Attr
-
-
-type Image
-    = Image String
-
-
-
--- IMAGES
-
-
-error : Image
-error =
-    image "error.jpg"
-
-
-loading : Image
-loading =
-    image "loading.svg"
-
-
-defaultAvatar : Image
-defaultAvatar =
-    image "smiley-cyrus.jpg"
-
-
-image : String -> Image
-image filename =
-    Image ("/assets/images/" ++ filename)
-
-
-
--- USING IMAGES
-
-
-src : Image -> Attribute msg
-src (Image url) =
-    Attr.src url
diff --git a/elm-deprecated/src/Avatar.elm b/elm-deprecated/src/Avatar.elm
deleted file mode 100644
index 7ecafb3..0000000
--- a/elm-deprecated/src/Avatar.elm
+++ /dev/null
@@ -1,56 +0,0 @@
-module Avatar exposing (Avatar, decoder, encode, src, toMaybeString)
-
-import Asset
-import Html exposing (Attribute)
-import Html.Attributes
-import Json.Decode as Decode exposing (Decoder)
-import Json.Encode as Encode exposing (Value)
-
-
-
--- TYPES
-
-
-type Avatar
-    = Avatar (Maybe String)
-
-
-
--- CREATE
-
-
-decoder : Decoder Avatar
-decoder =
-    Decode.map Avatar (Decode.nullable Decode.string)
-
-
-
--- TRANSFORM
-
-
-encode : Avatar -> Value
-encode (Avatar maybeUrl) =
-    case maybeUrl of
-        Just url ->
-            Encode.string url
-
-        Nothing ->
-            Encode.null
-
-
-src : Avatar -> Attribute msg
-src (Avatar maybeUrl) =
-    case maybeUrl of
-        Nothing ->
-            Asset.src Asset.defaultAvatar
-
-        Just "" ->
-            Asset.src Asset.defaultAvatar
-
-        Just url ->
-            Html.Attributes.src url
-
-
-toMaybeString : Avatar -> Maybe String
-toMaybeString (Avatar maybeUrl) =
-    maybeUrl
diff --git a/elm-deprecated/src/CommonElements.elm b/elm-deprecated/src/CommonElements.elm
deleted file mode 100644
index 2a9bdd1..0000000
--- a/elm-deprecated/src/CommonElements.elm
+++ /dev/null
@@ -1,31 +0,0 @@
--- this is a list of common styled elements
-
-
-module CommonElements exposing (..)
-
-import Element exposing (..)
-import Element.Font as Font
-
-
-bolded : String -> Element msg
-bolded content =
-    el
-        [ Font.bold ]
-        (text content)
-
-
-namedLink : String -> String -> Element msg
-namedLink path name =
-    link []
-        { url = "/#" ++ path
-        , label = text name
-        }
-
-
-debugLog : a -> a
-debugLog value =
-    let
-        _ =
-            Debug.log "value: " value
-    in
-    value
diff --git a/elm-deprecated/src/Email.elm b/elm-deprecated/src/Email.elm
deleted file mode 100644
index 0181842..0000000
--- a/elm-deprecated/src/Email.elm
+++ /dev/null
@@ -1,38 +0,0 @@
-module Email exposing (Email, decoder, encode, toString)
-
-import Json.Decode as Decode exposing (Decoder)
-import Json.Encode as Encode exposing (Value)
-
-
-{-| An email address.
-Having this as a custom type that's separate from String makes certain
-mistakes impossible. Consider this function:
-updateEmailAddress : Email -> String -> Http.Request
-updateEmailAddress email password = ...
-(The server needs your password to confirm that you should be allowed
-to update the email address.)
-Because Email is not a type alias for String, but is instead a separate
-custom type, it is now impossible to mix up the argument order of the
-email and the password. If we do, it won't compile!
-If Email were instead defined as `type alias Email = String`, we could
-call updateEmailAddress password email and it would compile (and never
-work properly).
-This way, we make it impossible for a bug like that to compile!
--}
-type Email
-    = Email String
-
-
-toString : Email -> String
-toString (Email str) =
-    str
-
-
-encode : Email -> Value
-encode (Email str) =
-    Encode.string str
-
-
-decoder : Decoder Email
-decoder =
-    Decode.map Email Decode.string
diff --git a/elm-deprecated/src/Home.elm b/elm-deprecated/src/Home.elm
deleted file mode 100644
index 462b0a2..0000000
--- a/elm-deprecated/src/Home.elm
+++ /dev/null
@@ -1,9 +0,0 @@
-module Home exposing (..)
-
-import Element exposing (..)
-import Model exposing (..)
-
-
-getPage : Model -> Element Msg
-getPage _ =
-    text "Home page."
diff --git a/elm-deprecated/src/Login.elm b/elm-deprecated/src/Login.elm
deleted file mode 100644
index 9aa8067..0000000
--- a/elm-deprecated/src/Login.elm
+++ /dev/null
@@ -1,40 +0,0 @@
-module Login exposing (..)
-
-import CommonElements exposing (..)
-import Element exposing (..)
-import Element.Input as Input
-import Model exposing (..)
-
-
-getPage : Model -> Element Msg
-getPage model =
-    column []
-        [ loginBox model
-        , namedLink "/signup" "Sign Up"
-        ]
-
-
-loginBox : Model -> Element Msg
-loginBox model =
-    column []
-        [ text "Log in"
-        , Input.email
-            [ Input.focusedOnLoad
-            ]
-            { onChange = CredentialsChange "loginUsername"
-            , text = Maybe.withDefault "" model.storage.loginUsername
-            , placeholder = Just (Input.placeholder [] (text ""))
-            , label = Input.labelHidden "email"
-            }
-        , Input.currentPassword []
-            { onChange = CredentialsChange "loginPassword"
-            , text = Maybe.withDefault "" model.storage.loginPassword
-            , placeholder = Just (Input.placeholder [] (text ""))
-            , label = Input.labelHidden "password"
-            , show = False
-            }
-        , Input.button []
-            { onPress = Just SubmitLogin
-            , label = text "Log In"
-            }
-        ]
diff --git a/elm-deprecated/src/Main.elm b/elm-deprecated/src/Main.elm
deleted file mode 100644
index c1166ca..0000000
--- a/elm-deprecated/src/Main.elm
+++ /dev/null
@@ -1,178 +0,0 @@
-module Main exposing (..)
-
-import Browser
-import Browser.Navigation as Nav
-import CommonElements exposing (..)
-import Element exposing (..)
-import NavRow exposing (..)
-import PageState exposing (..)
-import Session exposing (Session)
-import Url
-import Viewer exposing (..)
-
-
-type Model
-    = Redirect Session
-    | NotFound Session
-    | About Session
-    | Home Home.Model
-    | Account Account.Model
-    | Login Login.Model
-    | Signup Signup.Model
-    | Todo Todo.Model
-    | Editor (Maybe UUID) Editor.Model
-
-
-type Msg
-    = UrlChange Url.Url
-    | Request Browser.UrlRequest
-    | GotHomeMsg Home.Msg
-    | GotAccountMsg Account.Msg
-    | GotLoginMsg Login.Msg
-    | GotSignupMsg Signup.Msg
-    | GotEditorMsg Editor.Msg
-    | GotTodoMsg Todo.Msg
-    | GotSession Session
-
-
-init : Maybe Viewer -> Url.Url -> Nav.Key -> ( Model, Cmd Msg )
-init maybeViewer url key =
-    changeRouteTo (Route.fromUrl url)
-        (Redirect (Session.fromViewer navKey maybeViewer))
-
-
-toSession : Model -> Session
-toSession page =
-    case page of
-        Redirect session ->
-            session
-
-        NotFound session ->
-            session
-
-        About session ->
-            session
-
-        Home home ->
-            Home.toSession home
-
-        Account settings ->
-            Settings.toSession settings
-
-        Login login ->
-            Login.toSession login
-
-        Signup signup ->
-            Signup.toSession signup
-
-        Todo todo ->
-            Todo.toSession todo
-
-        Editor _ editor ->
-            Editor.toSession editor
-
-
-changeRouteTo : Maybe Route -> Model -> ( Model, Cmd Msg )
-changeRouteTo maybeRoute model =
-    let
-        session =
-            toSession model
-    in
-    case maybeRoute of
-        Nothing ->
-            ( NotFound session, Cmd.none )
-
-        Just Route.Root ->
-            ( model, Route.replaceUrl (Session.navKey session) Route.Home )
-
-        Just Route.Logout ->
-            ( model, Api.logout )
-
-        Just Route.NewTodo ->
-            Editor.initNew session
-                |> updateWith (Editor Nothing) GotEditorMsg model
-
-        Just (Route.EditTodo slug) ->
-            Editor.initEdit session slug
-                |> updateWith (Editor (Just slug)) GotEditorMsg model
-
-        Just Route.Account ->
-            Account.init session
-                |> updateWith Account GotAccountMsg model
-
-        Just Route.Home ->
-            Home.init session
-                |> updateWith Home GotHomeMsg model
-
-        Just Route.Login ->
-            Login.init session
-                |> updateWith Login GotLoginMsg model
-
-        Just Route.Signup ->
-            Signup.init session
-                |> updateWith Signup GotSignupMsg model
-
-        Just (Route.Profile username) ->
-            Profile.init session username
-                |> updateWith (Profile username) GotProfileMsg model
-
-        Just (Route.Todo slug) ->
-            Todo.init session slug
-                |> updateWith Todo GotArticleMsg model
-
-
-update : Msg -> Model -> ( Model, Cmd Msg )
-update msg model =
-    case ( msg, model ) of
-        ( _, _ ) ->
-            ( model, Cmd.none )
-
-
-updateWith : (subModel -> Model) -> (subMsg -> Msg) -> Model -> ( subModel, Cmd subMsg ) -> ( Model, Cmd Msg )
-updateWith toModel toMsg model ( subModel, subCmd ) =
-    ( toModel subModel
-    , Cmd.map toMsg subCmd
-    )
-
-
-
--- view takes current application state and is responsible
--- for rendering the document based on it
-
-
-view : Model -> Browser.Document Msg
-view model =
-    { title = "Elm App Test"
-    , body =
-        [ layout [ height fill ]
-            (column [ width fill ]
-                [ getNavRow model
-                , getMainContent model
-                ]
-            )
-        ]
-    }
-
-
-
--- subscriptions takes the current state and
--- maybe returns the subscriptions based on it (?)
--- might be used to subscribe to different events based on
--- the url, etc.
-
-
-subscriptions : Model -> Sub Msg
-subscriptions _ =
-    Sub.none
-
-
-main : Program Value Model Msg
-main =
-    Api.application Viewer.decoder
-        { init = init
-        , view = view
-        , update = update
-        , subscriptions = subscriptions
-        , onUrlChange = UrlChange -- these are actual types from Msg
-        , onUrlRequest = Request
-        }
diff --git a/elm-deprecated/src/NavRow.elm b/elm-deprecated/src/NavRow.elm
deleted file mode 100644
index 9edcd2d..0000000
--- a/elm-deprecated/src/NavRow.elm
+++ /dev/null
@@ -1,57 +0,0 @@
-module NavRow exposing (..)
-
-import CommonElements exposing (..)
-import Element exposing (..)
-import Element.Region as Region
-import Model exposing (..)
-import Request exposing (..)
-import Url
-
-
-getNavRow : Model -> Element Msg
-getNavRow model =
-    row
-        [ Region.navigation
-
-        --, explain Debug.todo
-        , paddingXY 10 5
-        , spacing 10
-        , width fill
-        ]
-        [ namedLink "/" "TODOAPP"
-        , getDebugInfo model
-        , getCurrentUser model
-        ]
-
-
-
--- temp function to get current page url
--- and links in case shit breaks
-
-
-getDebugInfo : Model -> Element Msg
-getDebugInfo model =
-    row
-        [ centerX ]
-        [ text "Current URL: "
-        , bolded (Url.toString model.url)
-        , column []
-            [ namedLink "/" "root"
-            , namedLink "/login" "login"
-            , namedLink "/signup" "signup"
-            , namedLink "/account" "account"
-            , namedLink "/about" "about"
-            ]
-        ]
-
-
-getCurrentUser : Model -> Element Msg
-getCurrentUser model =
-    el []
-        (case model.user of
-            Just user ->
-                namedLink "/account" user.email
-
-            _ ->
-                namedLink "/login" "Log In"
-        )
diff --git a/elm-deprecated/src/PageState.elm b/elm-deprecated/src/PageState.elm
deleted file mode 100644
index e2982fd..0000000
--- a/elm-deprecated/src/PageState.elm
+++ /dev/null
@@ -1,66 +0,0 @@
-module PageState exposing (getMainContent)
-
-import About as AboutPage
-import Account as AccountPage
-import Element exposing (..)
-import Home as HomePage
-import Login as LoginPage
-import Model exposing (..)
-import Signup as SignupPage
-import Url
-import Url.Parser as Parser exposing (..)
-
-
-type Route
-    = About
-    | Account
-    | Home
-    | Login
-    | Signup
-    | NotFound
-
-
-getMainContent : Model -> Element Msg
-getMainContent model =
-    el []
-        (case consume (toRoute model.url) of
-            About ->
-                AboutPage.getPage model
-
-            Account ->
-                AccountPage.getPage model
-
-            Home ->
-                HomePage.getPage model
-
-            Login ->
-                LoginPage.getPage model
-
-            Signup ->
-                SignupPage.getPage model
-
-            _ ->
-                text "Page not found."
-        )
-
-
-routeParser : Parser (Route -> a) a
-routeParser =
-    oneOf
-        [ Parser.map Home top
-        , Parser.map Account (s "account")
-        , Parser.map About (s "about")
-        , Parser.map Login (s "login")
-        , Parser.map Signup (s "signup")
-        ]
-
-
-toRoute : Url.Url -> Maybe Route
-toRoute url =
-    { url | path = Maybe.withDefault "" url.fragment, fragment = Nothing }
-        |> Parser.parse routeParser
-
-
-consume : Maybe Route -> Route
-consume route =
-    Maybe.withDefault NotFound route
diff --git a/elm-deprecated/src/Route.elm b/elm-deprecated/src/Route.elm
deleted file mode 100644
index 484d8a9..0000000
--- a/elm-deprecated/src/Route.elm
+++ /dev/null
@@ -1,98 +0,0 @@
-module Route exposing (Route(..), fromUrl, href, replaceUrl)
-
-import Browser.Navigation as Nav
-import Html exposing (Attribute)
-import Html.Attributes as Attr
-import Todo.UUID as UUID
-import Url exposing (Url)
-import Url.Parser as Parser exposing ((), Parser, oneOf, s, string)
-import Username exposing (Username)
-
-
-
--- ROUTING
-
-
-type Route
-    = Home
-    | Login
-    | Logout
-    | Signup
-    | Account
-    | Todo UUID.UUID
-    | NewTodo
-    | EditTodo UUID.UUID
-
-
-parser : Parser (Route -> a) a
-parser =
-    oneOf
-        [ Parser.map Home Parser.top
-        , Parser.map Login (s "login")
-        , Parser.map Logout (s "logout")
-        , Parser.map Account (s "account")
-        , Parser.map Signup (s "signup")
-        , Parser.map Todo (s "article"  UUID.urlParser)
-        , Parser.map NewTodo (s "editor")
-        , Parser.map EditTodo (s "editor"  UUID.urlParser)
-        ]
-
-
-
--- PUBLIC HELPERS
-
-
-href : Route -> Attribute msg
-href targetRoute =
-    Attr.href (routeToString targetRoute)
-
-
-replaceUrl : Nav.Key -> Route -> Cmd msg
-replaceUrl key route =
-    Nav.replaceUrl key (routeToString route)
-
-
-fromUrl : Url -> Maybe Route
-fromUrl url =
-    -- The RealWorld spec treats the fragment like a path.
-    -- This makes it *literally* the path, so we can proceed
-    -- with parsing as if it had been a normal path all along.
-    { url | path = Maybe.withDefault "" url.fragment, fragment = Nothing }
-        |> Parser.parse parser
-
-
-
--- INTERNAL
-
-
-routeToString : Route -> String
-routeToString page =
-    "#/" ++ String.join "/" (routeToPieces page)
-
-
-routeToPieces : Route -> List String
-routeToPieces page =
-    case page of
-        Home ->
-            []
-
-        Login ->
-            [ "login" ]
-
-        Logout ->
-            [ "logout" ]
-
-        Signup ->
-            [ "Signup" ]
-
-        Account ->
-            [ "account" ]
-
-        Todo uuid ->
-            [ "article", UUID.toString uuid ]
-
-        NewTodo ->
-            [ "editor" ]
-
-        EditTodo uuid ->
-            [ "editor", UUID.toString uuid ]
diff --git a/elm-deprecated/src/Session.elm b/elm-deprecated/src/Session.elm
deleted file mode 100644
index 2a8e994..0000000
--- a/elm-deprecated/src/Session.elm
+++ /dev/null
@@ -1,75 +0,0 @@
-module Session exposing (Session, changes, cred, fromViewer, navKey, viewer)
-
-import Api exposing (Cred)
-import Avatar exposing (Avatar)
-import Browser.Navigation as Nav
-import Json.Decode as Decode exposing (Decoder)
-import Json.Encode as Encode exposing (Value)
-import Profile exposing (Profile)
-import Time
-import Viewer exposing (Viewer)
-
-
-
--- TYPES
-
-
-type Session
-    = LoggedIn Nav.Key Viewer
-    | Guest Nav.Key
-
-
-
--- INFO
-
-
-viewer : Session -> Maybe Viewer
-viewer session =
-    case session of
-        LoggedIn _ val ->
-            Just val
-
-        Guest _ ->
-            Nothing
-
-
-cred : Session -> Maybe Cred
-cred session =
-    case session of
-        LoggedIn _ val ->
-            Just (Viewer.cred val)
-
-        Guest _ ->
-            Nothing
-
-
-navKey : Session -> Nav.Key
-navKey session =
-    case session of
-        LoggedIn key _ ->
-            key
-
-        Guest key ->
-            key
-
-
-
--- CHANGES
-
-
-changes : (Session -> msg) -> Nav.Key -> Sub msg
-changes toMsg key =
-    Api.viewerChanges (\maybeViewer -> toMsg (fromViewer key maybeViewer)) Viewer.decoder
-
-
-fromViewer : Nav.Key -> Maybe Viewer -> Session
-fromViewer key maybeViewer =
-    -- It's stored in localStorage as a JSON String;
-    -- first decode the Value as a String, then
-    -- decode that String as JSON.
-    case maybeViewer of
-        Just viewerVal ->
-            LoggedIn key viewerVal
-
-        Nothing ->
-            Guest key
diff --git a/elm-deprecated/src/Signup.elm b/elm-deprecated/src/Signup.elm
deleted file mode 100644
index 64218be..0000000
--- a/elm-deprecated/src/Signup.elm
+++ /dev/null
@@ -1,53 +0,0 @@
-module Signup exposing (..)
-
-import CommonElements exposing (..)
-import Element exposing (..)
-import Element.Input as Input
-import Model exposing (..)
-
-
-getPage : Model -> Element Msg
-getPage model =
-    el [] (signupBox model)
-
-
-signupBox : Model -> Element Msg
-signupBox model =
-    column []
-        [ text "Sign up"
-        , Input.email
-            [ Input.focusedOnLoad
-            ]
-            { onChange = CredentialsChange "loginUsername"
-            , text = Maybe.withDefault "" model.storage.loginUsername
-            , placeholder = Just (Input.placeholder [] (text "email"))
-            , label = Input.labelHidden "email"
-            }
-        , Input.newPassword []
-            { onChange = CredentialsChange "loginPassword"
-            , text = Maybe.withDefault "" model.storage.loginPassword
-            , placeholder = Just (Input.placeholder [] (text "password"))
-            , label = Input.labelHidden "password"
-            , show = False
-            }
-        , Input.newPassword []
-            { onChange = CredentialsChange "confirmPassword"
-            , text = Maybe.withDefault "" model.storage.signupConfirmPassword
-            , placeholder = Just (Input.placeholder [] (text "confirm password"))
-            , label = Input.labelHidden "confirm password"
-            , show = False
-            }
-        , Input.button []
-            { onPress = ensurePasswordMatch model
-            , label = text "Sign Up"
-            }
-        ]
-
-
-ensurePasswordMatch : Model -> Maybe Msg
-ensurePasswordMatch model =
-    if model.storage.signupConfirmPassword == model.storage.loginPassword then
-        Just SubmitSignup
-
-    else
-        Just SignupPasswordMismatch
diff --git a/elm-deprecated/src/Todo.elm b/elm-deprecated/src/Todo.elm
deleted file mode 100644
index 2e97eef..0000000
--- a/elm-deprecated/src/Todo.elm
+++ /dev/null
@@ -1,253 +0,0 @@
-module Todo exposing (Full, Preview, Todo, author, body, favorite, favoriteButton, fetch, fromPreview, fullDecoder, mapAuthor, metadata, previewDecoder, unfavorite, unfavoriteButton, uuid)
-
-{-| The interface to the Todo data structure.
-This includes:
-
-  - The Todo type itself
-  - Ways to make HTTP requests to retrieve and modify Todos
-  - Ways to access information about an Todo
-  - Converting between various types
-
--}
-
-import Api exposing (Cred)
-import Api.Endpoint as Endpoint
-import Author exposing (Author)
-import Element exposing (..)
-import Http
-import Iso8601
-import Json.Decode as Decode exposing (Decoder)
-import Json.Encode as Encode
-import Markdown
-import Time
-import Todo.Body as Body exposing (Body)
-import Todo.Tag as Tag exposing (Tag)
-import Todo.UUID exposing (UUID)
-import Username as Username exposing (Username)
-import Viewer exposing (Viewer)
-
-
-
--- TYPES
-
-
-{-| An Todo, optionally with an Todo body.
-To see the difference between { extraInfo : a } and { extraInfo : Maybe Body },
-consider the difference between the "view individual Todo" page (which
-renders one Todo, including its body) and the "Todo feed" -
-which displays multiple Todos, but without bodies.
-This definition for `Todo` means we can write:
-viewTodo : Todo Full -> Html msg
-viewFeed : List (Todo Preview) -> Html msg
-This indicates that `viewTodo` requires an Todo _with a `body` present_,
-wereas `viewFeed` accepts Todos with no bodies. (We could also have written
-it as `List (Todo a)` to specify that feeds can accept either Todos that
-have `body` present or not. Either work, given that feeds do not attempt to
-read the `body` field from Todos.)
-This is an important distinction, because in Request.Todo, the `feed`
-function produces `List (Todo Preview)` because the API does not return bodies.
-Those Todos are useful to the feed, but not to the individual Todo view.
--}
-type Todo a
-    = Todo Internals a
-
-
-{-| Metadata about the Todo - its title, description, and so on.
-Importantly, this module's public API exposes a way to read this metadata, but
-not to alter it. This is read-only information!
-If we find ourselves using any particular piece of metadata often,
-for example `title`, we could expose a convenience function like this:
-Todo.title : Todo a -> String
-If you like, it's totally reasonable to expose a function like that for every one
-of these fields!
-(Okay, to be completely honest, exposing one function per field is how I prefer
-to do it, and that's how I originally wrote this module. However, I'm aware that
-this code base has become a common reference point for beginners, and I think it
-is _extremely important_ that slapping some "getters and setters" on a record
-does not become a habit for anyone who is getting started with Elm. The whole
-point of making the Todo type opaque is to create guarantees through
-_selectively choosing boundaries_ around it. If you aren't selective about
-where those boundaries are, and instead expose a "getter and setter" for every
-field in the record, the result is an API with no more guarantees than if you'd
-exposed the entire record directly! It is so important to me that beginners not
-fall into the terrible "getters and setters" trap that I've exposed this
-Metadata record instead of exposing a single function for each of its fields,
-as I did originally. This record is not a bad way to do it, by any means,
-but if this seems at odds with  - now you know why!
-)
--}
-type alias Metadata =
-    { description : String
-    , title : String
-    , tags : List String
-    , createdAt : Time.Posix
-    , favorited : Bool
-    , favoritesCount : Int
-    }
-
-
-type alias Internals =
-    { uuid : UUID
-    , author : Author
-    , metadata : Metadata
-    }
-
-
-type Preview
-    = Preview
-
-
-type Full
-    = Full Body
-
-
-
--- INFO
-
-
-author : Todo a -> Author
-author (Todo internals _) =
-    internals.author
-
-
-metadata : Todo a -> Metadata
-metadata (Todo internals _) =
-    internals.metadata
-
-
-uuid : Todo a -> UUID
-uuid (Todo internals _) =
-    internals.uuid
-
-
-body : Todo Full -> Body
-body (Todo _ (Full extraInfo)) =
-    extraInfo
-
-
-
--- TRANSFORM
-
-
-{-| This is the only way you can transform an existing Todo:
-you can change its author (e.g. to follow or unfollow them).
-All other Todo data necessarily comes from the server!
-We can tell this for sure by looking at the types of the exposed functions
-in this module.
--}
-mapAuthor : (Author -> Author) -> Todo a -> Todo a
-mapAuthor transform (Todo info extras) =
-    Todo { info | author = transform info.author } extras
-
-
-fromPreview : Body -> Todo Preview -> Todo Full
-fromPreview newBody (Todo info Preview) =
-    Todo info (Full newBody)
-
-
-
--- SERIALIZATION
-
-
-previewDecoder : Maybe Cred -> Decoder (Todo Preview)
-previewDecoder maybeCred =
-    Decode.succeed Todo
-        |> custom (internalsDecoder maybeCred)
-        |> hardcoded Preview
-
-
-fullDecoder : Maybe Cred -> Decoder (Todo Full)
-fullDecoder maybeCred =
-    Decode.succeed Todo
-        |> custom (internalsDecoder maybeCred)
-        |> required "body" (Decode.map Full Body.decoder)
-
-
-internalsDecoder : Maybe Cred -> Decoder Internals
-internalsDecoder maybeCred =
-    Decode.succeed Internals
-        |> required "uuid" UUID.decoder
-        |> required "author" (Author.decoder maybeCred)
-        |> custom metadataDecoder
-
-
-metadataDecoder : Decoder Metadata
-metadataDecoder =
-    Decode.succeed Metadata
-        |> required "description" (Decode.map (Maybe.withDefault "") (Decode.nullable Decode.string))
-        |> required "title" Decode.string
-        |> required "tagList" (Decode.list Decode.string)
-        |> required "createdAt" Iso8601.decoder
-        |> required "favorited" Decode.bool
-        |> required "favoritesCount" Decode.int
-
-
-
--- SINGLE
-
-
-fetch : Maybe Cred -> UUID -> Http.Request (Todo Full)
-fetch maybeCred uuid =
-    Decode.field "Todo" (fullDecoder maybeCred)
-        |> Api.get (Endpoint.Todo uuid) maybeCred
-
-
-
--- FAVORITE
-
-
-favorite : UUID -> Cred -> Http.Request (Todo Preview)
-favorite uuid cred =
-    Api.post (Endpoint.favorite uuid) (Just cred) Http.emptyBody (faveDecoder cred)
-
-
-unfavorite : UUID -> Cred -> Http.Request (Todo Preview)
-unfavorite uuid cred =
-    Api.delete (Endpoint.favorite uuid) cred Http.emptyBody (faveDecoder cred)
-
-
-faveDecoder : Cred -> Decoder (Todo Preview)
-faveDecoder cred =
-    Decode.field "Todo" (previewDecoder (Just cred))
-
-
-{-| This is a "build your own element" API.
-You pass it some configuration, followed by a `List (Attribute msg)` and a
-`List (Html msg)`, just like any standard Html element.
--}
-favoriteButton :
-    Cred
-    -> msg
-    -> List (Attribute msg)
-    -> List (Element msg)
-    -> Element msg
-favoriteButton _ msg attrs kids =
-    toggleFavoriteButton "btn btn-sm btn-outline-primary" msg attrs kids
-
-
-unfavoriteButton :
-    Cred
-    -> msg
-    -> List (Attribute msg)
-    -> List (Element msg)
-    -> Element msg
-unfavoriteButton _ msg attrs kids =
-    toggleFavoriteButton "btn btn-sm btn-primary" msg attrs kids
-
-
-toggleFavoriteButton :
-    String
-    -> msg
-    -> List (Attribute msg)
-    -> List (Element msg)
-    -> Element msg
-toggleFavoriteButton classStr msg attrs kids =
-    Html.button
-        (class classStr :: onClickStopPropagation msg :: attrs)
-        (i [ class "ion-heart" ] [] :: kids)
-
-
-onClickStopPropagation : msg -> Attribute msg
-onClickStopPropagation msg =
-    stopPropagationOn "click"
-        (Decode.succeed ( msg, True ))
diff --git a/elm-deprecated/src/Todo/UUID.elm b/elm-deprecated/src/Todo/UUID.elm
deleted file mode 100644
index bd200f1..0000000
--- a/elm-deprecated/src/Todo/UUID.elm
+++ /dev/null
@@ -1,35 +0,0 @@
-module Todo.UUID exposing (UUID, decoder, toString, urlParser)
-
-import Json.Decode as Decode exposing (Decoder)
-import Url.Parser exposing (Parser)
-
-
-
--- TYPES
-
-
-type UUID
-    = UUID String
-
-
-
--- CREATE
-
-
-urlParser : Parser (UUID -> a) a
-urlParser =
-    Url.Parser.custom "UUID" (\str -> Just (UUID str))
-
-
-decoder : Decoder UUID
-decoder =
-    Decode.map UUID Decode.string
-
-
-
--- TRANSFORM
-
-
-toString : UUID -> String
-toString (UUID str) =
-    str
diff --git a/elm-deprecated/src/Username.elm b/elm-deprecated/src/Username.elm
deleted file mode 100644
index 781104d..0000000
--- a/elm-deprecated/src/Username.elm
+++ /dev/null
@@ -1,47 +0,0 @@
-module Username exposing (Username, decoder, encode, toHtml, toString, urlParser)
-
-import Element exposing (..)
-import Json.Decode as Decode exposing (Decoder)
-import Json.Encode as Encode exposing (Value)
-import Url.Parser
-
-
-
--- TYPES
-
-
-type Username
-    = Username String
-
-
-
--- CREATE
-
-
-decoder : Decoder Username
-decoder =
-    Decode.map Username Decode.string
-
-
-
--- TRANSFORM
-
-
-encode : Username -> Value
-encode (Username username) =
-    Encode.string username
-
-
-toString : Username -> String
-toString (Username username) =
-    username
-
-
-urlParser : Url.Parser.Parser (Username -> a) a
-urlParser =
-    Url.Parser.custom "USERNAME" (\str -> Just (Username str))
-
-
-toHtml : Username -> Element msg
-toHtml (Username username) =
-    text username
diff --git a/elm-deprecated/src/Viewer.elm b/elm-deprecated/src/Viewer.elm
deleted file mode 100644
index 58ec005..0000000
--- a/elm-deprecated/src/Viewer.elm
+++ /dev/null
@@ -1,66 +0,0 @@
-module Viewer exposing (Viewer, avatar, cred, decoder, minPasswordChars, store, username)
-
-{-| The logged-in user currently viewing this page. It stores enough data to
-be able to render the menu bar (username and avatar), along with Cred so it's
-impossible to have a Viewer if you aren't logged in.
--}
-
-import Api exposing (Cred)
-import Avatar exposing (Avatar)
-import Email exposing (Email)
-import Json.Decode as Decode exposing (Decoder)
-import Json.Decode.Pipeline exposing (custom, required)
-import Json.Encode as Encode exposing (Value)
-import Profile exposing (Profile)
-import Username exposing (Username)
-
-
-
--- TYPES
-
-
-type Viewer
-    = Viewer Avatar Cred
-
-
-
--- INFO
-
-
-cred : Viewer -> Cred
-cred (Viewer _ val) =
-    val
-
-
-username : Viewer -> Username
-username (Viewer _ val) =
-    Api.username val
-
-
-avatar : Viewer -> Avatar
-avatar (Viewer val _) =
-    val
-
-
-{-| Passwords must be at least this many characters long!
--}
-minPasswordChars : Int
-minPasswordChars =
-    6
-
-
-
--- SERIALIZATION
-
-
-decoder : Decoder (Cred -> Viewer)
-decoder =
-    Decode.succeed Viewer
-        |> custom (Decode.field "image" Avatar.decoder)
-
-
-store : Viewer -> Cmd msg
-store (Viewer avatarVal credVal) =
-    Api.storeCredWith
-        credVal
-        avatarVal
diff --git a/todo/package.json b/package.json
similarity index 62%
rename from todo/package.json
rename to package.json
index fd35f15..2bcaeaf 100644
--- a/todo/package.json
+++ b/package.json
@@ -4,10 +4,6 @@
   "description": "todo list app (because it hasnt been done before)",
   "main": "src/index.js",
   "scripts": {
-    "who": "pwd",
-    "build": "cd frontend; elm make src/Main.elm --output=../static/elm.js",
-    "debug": "cd frontend; elm make src/Main.elm --debug --output=../static/elm.js",
-    "prod": "cd frontend; elm make src/Main.elm --optimize --output=../static/elm.js",
     "start": "node src/index.js"
   },
   "repository": {
@@ -18,9 +14,8 @@
   "license": "SEE LICENSE IN LICENSE",
   "dependencies": {
     "cookie-parser": "^1.4.5",
-    "cors": "^2.8.5",
     "express": "^4.17.1",
     "pg": "^8.6.0",
     "sequelize": "^6.6.2"
   }
-}
\ No newline at end of file
+}
diff --git a/todo/pnpm-lock.yaml b/pnpm-lock.yaml
similarity index 97%
rename from todo/pnpm-lock.yaml
rename to pnpm-lock.yaml
index 1b8148f..7711e79 100644
--- a/todo/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1,6 +1,5 @@
 dependencies:
   cookie-parser: 1.4.5
-  cors: 2.8.5
   express: 4.17.1
   pg: 8.6.0
   sequelize: 6.6.2_pg@8.6.0
@@ -89,15 +88,6 @@ packages:
       node: '>= 0.6'
     resolution:
       integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
-  /cors/2.8.5:
-    dependencies:
-      object-assign: 4.1.1
-      vary: 1.1.2
-    dev: false
-    engines:
-      node: '>= 0.10'
-    resolution:
-      integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
   /debug/2.6.9:
     dependencies:
       ms: 2.0.0
@@ -343,12 +333,6 @@ packages:
       node: '>= 0.6'
     resolution:
       integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
-  /object-assign/4.1.1:
-    dev: false
-    engines:
-      node: '>=0.10.0'
-    resolution:
-      integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
   /on-finished/2.3.0:
     dependencies:
       ee-first: 1.1.1
@@ -695,7 +679,6 @@ packages:
       integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
 specifiers:
   cookie-parser: ^1.4.5
-  cors: ^2.8.5
   express: ^4.17.1
   pg: ^8.6.0
   sequelize: ^6.6.2
diff --git a/todo/src/config.js b/src/config.js
similarity index 100%
rename from todo/src/config.js
rename to src/config.js
diff --git a/todo/src/db_interface.js b/src/db_interface.js
similarity index 100%
rename from todo/src/db_interface.js
rename to src/db_interface.js
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..af37430
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,39 @@
+const express = require('express');
+const cookieParser = require('cookie-parser');
+const Config = require('./config.js');
+
+const UserInterface = require('./user.js');
+
+let app = express();
+
+app.use(cookieParser());
+
+// force https
+app.use((req, res, next) => {
+  if (Config.config.https) {
+    if (req.headers['x-forwarded-proto'] !== 'https') {
+      return res.redirect(`https://${req.headers.host}${req.url}`);
+    }
+  }
+  return next();
+});
+
+if (!Config.config.secret) {
+  console.error("No password secret found. please set `secret` in config.json");
+  process.exit();
+}
+else if(Config.config.https && Config.config.secret == "TEST_SECRET") {
+  console.error("please do not use the testing secret in production.");
+  process.exit();
+}
+
+app.use("/user", UserInterface.router);
+
+// serve static files last
+// app.use(express.static("./static"));
+// DISABLED: no longer needs to serve static files
+// due to frontend being employed in elm
+
+app.listen(Config.config.port || 8080, () => {
+  console.log(`listening on port ${Config.config.port || 8080}`);
+});
\ No newline at end of file
diff --git a/todo/src/user.js b/src/user.js
similarity index 59%
rename from todo/src/user.js
rename to src/user.js
index 980cb77..2563baf 100644
--- a/todo/src/user.js
+++ b/src/user.js
@@ -13,19 +13,16 @@ user_cache = {};
 email_cache = {};
 
 async function get_user_details(id) {
-  if (!id) {
-    return undefined;
-  }
   console.log(`search for user with id ${id}`);
   if (!user_cache[id]) {
-    let user = await Database.schemas.user.findOne({where: {id: id}});
+    let user = await Database.schemas.user.findOne({ where: { id: id } });
     if (!user) {
       return undefined;
     }
     user_cache[user.id] = {
       id: user.id,
       email: user.email,
-      password_hash: user.password_hash,
+      password_hash: user.password_hash
     };
     email_cache[user.email] = user.id;
   }
@@ -34,19 +31,16 @@ async function get_user_details(id) {
 }
 
 async function get_user_details_by_email(email) {
-  if (!email) {
-    return undefined;
-  }
   console.log(`search for user with email ${email}}`);
   if (!email_cache[email] || !user_cache[email_cache[email]]) {
-    let user = await Database.schemas.user.findOne({where: {email: email}});
+    let user = await Database.schemas.user.findOne({ where: { email: email } });
     if (!user) {
       return undefined;
     }
     user_cache[user.id] = {
       id: user.id,
       email: user.email,
-      password_hash: user.password_hash,
+      password_hash: user.password_hash
     };
     email_cache[user.email] = user.id;
   }
@@ -54,10 +48,10 @@ async function get_user_details_by_email(email) {
   return user_cache[email_cache[email]];
 }
 
-router.get('/byEmail/:email', async (req, res) => {
+router.get("/byEmail/:email", async (req, res) => {
   if (!req.params?.email) {
     res.status(400).json({
-      error: 'email is a required parameter',
+      error: "email is a required parameter"
     });
   }
   let user = get_user_details_by_email(req.params.email);
@@ -65,33 +59,30 @@ router.get('/byEmail/:email', async (req, res) => {
   if (user != null) {
     res.json({
       id: user.id,
-      email: user.email,
+      email: user.email
     });
-  } else {
+  }
+  else {
     res.sendStatus(404);
   }
 });
 
 function hash(secret, password) {
-  let pw_hash = crypto.pbkdf2Sync(
-    password,
+  let pw_hash = crypto.pbkdf2Sync(password,
     secret,
     Config.config.key?.iterations || 1000,
     Config.config.key?.length || 64,
-    'sha512'
-  );
+    "sha512");
 
   return pw_hash.toString('base64');
 }
 
 function verify(secret, password, hash) {
-  let pw_hash = crypto.pbkdf2Sync(
-    password,
+  let pw_hash = crypto.pbkdf2Sync(password,
     secret,
     Config.config.key?.iterations || 1000,
     Config.config.key?.length || 64,
-    'sha512'
-  );
+    "sha512");
 
   return hash === pw_hash.toString('base64');
 }
@@ -112,7 +103,8 @@ function get_session_token(id, token) {
 function verify_session_token(id, hash, token) {
   if (session_entropy[id]) {
     return verify(session_entropy[id], hash, token);
-  } else {
+  }
+  else {
     return false;
   }
 }
@@ -120,116 +112,106 @@ function verify_session_token(id, hash, token) {
 async function enforce_session_login(req, res, next) {
   let userid = req.cookies?.userid;
   let session_token = req.cookies?._session;
-  console.log('a', userid, session_token);
+  console.log("a", userid, session_token);
   if (!userid || !session_token) {
-    return res.sendStatus(401);
+    res.sendStatus(401);
   }
   let user = await get_user_details(userid);
   if (!user) {
-    return res.sendStatus(401);
+    res.sendStatus(401);
   }
-  let verified_session = verify_session_token(
-    userid,
-    user.password_hash,
-    session_token
-  );
+  let verified_session = verify_session_token(userid, user.password_hash, session_token);
   if (!verified_session) {
-    return res.sendStatus(401);
+    res.sendStatus(401);
   }
   return next();
 }
 
-router.post('/new', async (req, res) => {
+router.post("/new", async (req, res) => {
   if (!req.body?.email || !req.body?.password) {
-    return res.status(400).json({
-      error: 'must have email and password fields',
+    res.status(400).json({
+      error: "must have email and password fields"
     });
   }
   let user = await get_user_details_by_email(req.body.email);
   console.log(user);
   if (user != null) {
-    return res.status(403).json({
-      error: `email ${req.body.email} is already in use.`,
+    res.status(403).json({
+      error: `email ${req.body.email} is already in use.`
     });
-  } else {
+  }
+  else {
     let user = await Database.schemas.user.create({
       email: String(req.body.email),
-      password_hash: hash_password(req.body.password),
+      password_hash: hash_password(req.body.password)
     });
 
-    return res.json({
+    res.json({
       id: user.id,
-      email: user.email,
+      email: user.email
     });
   }
 });
 
-router.post('/login', async (req, res) => {
+router.post("/login", async (req, res) => {
   if (!req.body?.email || !req.body?.password) {
-    return res.status(400).json({
-      error: 'must have email and password fields',
+    res.status(400).json({
+      error: "must have email and password fields"
     });
   }
   let user = await get_user_details_by_email(req.body.email);
   if (!user) {
-    return res.status(401).json({
-      error: 'incorrect email or password',
+    res.status(401).json({
+      error: "incorrect email or password"
     });
   }
   let verified = verify_password(req.body.password, user.password_hash);
 
   if (!verified) {
-    return res.status(401).json({
-      error: 'incorrect email or password',
+    res.status(401).json({
+      error: "incorrect email or password"
     });
   }
 
-  res.cookie('userid', user.id, {
-    httpOnly: true,
-    secure: true,
-  });
-  res.cookie('_session', get_session_token(user.id, user.password_hash), {
-    httpOnly: true,
-    secure: true,
-  });
-  return res.sendStatus(204);
+  res.cookie("userid", user.id);
+  res.cookie("_session", get_session_token(user.id, user.password_hash));
+  res.sendStatus(204);
 });
 
-router.get('/:id([a-f0-9-]+)', async (req, res) => {
-  console.log(req.params);
+router.get("/:id(([a-f0-9\-])+)", async (req, res) => {
   if (!req.params?.id) {
-    return res.status(400).json({
-      error: 'must have id parameter',
+    res.status(400).json({
+      error: "must have id parameter"
     });
   }
-  let id = req.params?.id;
-  console.log(id);
-  let user = await get_user_details(id);
+  let user = await get_user_details(req.body.id);
   console.log(user);
   if (user != null) {
-    return res.json({
+    res.json({
       id: user.id,
-      email: user.email,
+      email: user.email
     });
-  } else {
-    return res.sendStatus(404);
+  }
+  else {
+    res.sendStatus(404);
   }
 });
 
-router.use('/authorized', enforce_session_login);
-router.get('/authorized', async (req, res) => {
+router.use("/authorized", enforce_session_login);
+router.get("/authorized", async (req, res) => {
   let userid = req.cookies?.userid;
-  let user = await get_user_details(userid);
-  return res.json({
+  let user = get_user_details(userid);
+  res.json({
     authorized: true,
     user: {
       id: user.id,
-      email: user.email,
-    },
+      email: user.email
+    }
   });
 });
 
+
 module.exports = {
   router: router,
-  enforce_session_login: enforce_session_login,
-};
+  enforce_session_login: enforce_session_login
+};
\ No newline at end of file
diff --git a/static/index.html b/static/index.html
new file mode 100644
index 0000000..ec57bad
--- /dev/null
+++ b/static/index.html
@@ -0,0 +1,8 @@
+
+  
+    
+  
+  
+
+  
+
\ No newline at end of file
diff --git a/todo/src/index.js b/todo/src/index.js
deleted file mode 100644
index 8c86ac0..0000000
--- a/todo/src/index.js
+++ /dev/null
@@ -1,62 +0,0 @@
-const http = require('http');
-const https = require('https');
-const cors = require('cors');
-const express = require('express');
-const cookieParser = require('cookie-parser');
-const Config = require('./config.js');
-
-const UserInterface = require('./user.js');
-
-let credentials = {};
-
-if (Config.config.https) {
-  if (
-    fs.existsSync(Config.config.cert) &&
-    fs.existsSync(Config.config.cert_key)
-  ) {
-    credentials.key = fs.readFileSync(Config.config.cert_key);
-    credentials.cert = fs.readFileSync(Config.config.cert);
-  }
-}
-
-let app = express();
-
-app.use(cors());
-app.use(cookieParser());
-
-// force https
-app.use((req, res, next) => {
-  if (Config.config.https) {
-    if (req.headers['x-forwarded-proto'] !== 'https') {
-      return res.redirect(`https://${req.headers.host}${req.url}`);
-    }
-  }
-  return next();
-});
-
-if (!Config.config.secret) {
-  console.error('No password secret found. please set `secret` in config.json');
-  process.exit();
-} else if (Config.config.https && Config.config.secret == 'TEST_SECRET') {
-  console.error('please do not use the testing secret in production.');
-  process.exit();
-}
-
-app.use('/api/user', UserInterface.router);
-
-// serve static files last
-app.use(express.static('./static'));
-// DISABLED: no longer needs to serve static files
-// due to frontend being employed in elm
-
-if (Config.config.https) {
-  var server = https.createServer(credentials, app);
-  server.listen(Config.config.port || 8080);
-} else {
-  var server = http.createServer(app);
-  server.listen(Config.config.port || 8080);
-}
-console.log(
-  `listening on port ${Config.config.port || 8080}` +
-    ` with https ${Config.config.https ? 'enabled' : 'disabled'}`
-);