This is a SvelteKit application that allows you to order food from restaurants, pay, and track your orders. It is written in TypeScript, and uses Amazon's DynamoDB as its database. Payments are implemented with Stripe. The app is deployed to Vercel, and the latest commit on master is accessible at prefood.miikat.dev. See the changelog and TODO list in CHANGELOG.md.
- Create an account with
- Github
- or just your email
- Edit profile information
- Upload your own photo
- Get a custom link to your profile
- Add API keys
- Pay for items through Stripe
- Use card no. 4242 4242 4242 4242 for testing
- Get an email receipt and an order-specific link
- See the OpenAPI documentation at /docs (in development)
- Dark mode
-
The load function in
routes/(app)/+layout.server.tsruns.- Loads the user's data if they're authenticated
- Generates a state token and makes sure it's also set as a cookie
-
routes/(app)/+layout.svelterenders the header and footer.- Adds the state token to the context
- Adds the
darkclass to<body>if localStorage hasdarkMode
-
lib/components/Login.svelterenders the login buttons.- In the
stateparameter to identity providers we pass:- If rememberMe is checked
- Whether we're logging in or linking the identity to an existing account
- What page the user came from
- The authentication method used
- The state token to prevent CSRF
- In the
-
The user gets redirected and
routes/(app)/account/login/server.tsruns.- The used authentication method is read from the passed
stateparameter. - A trusted identity (
googleID,githubIDoremail) is read from the URL and verified. - A new session token is generated and added to the user's account.
- The session token is concatenated with the userID to form an
AuthTokenwhich is set into a cookie. - The user is redirected to where they were based on the
stateparameter.
- The used authentication method is read from the passed
Steps 1 and 2 from the login flow are the same.
-
User selects food items in
routes/(app)/restaurants/[slug]/+page.svelteand triggers a SvelteKit action in+page.server.ts;- The items selected are parsed and checked that they correspond to actual menu items
- A Stripe checkout session is created and the user is redirected to it
-
Stripe's server calls
/routes/api/stripe-webhook/+server.ts, which adds the order to the database and emails a receipt. -
The user is redirected to
/orders, and their orders are displayed from the database
- There's three different tables:
users,restaurantsandprders. - (pk) = primary key
- (sk) = sort key
- (si) = there's a secondary index with an
-indexsuffix
| userID (pk) | googleID (si) | githubID (si) | email (si) | name | username | picture | sessionTokens | stripeCustomerID | apiKeys |
|---|---|---|---|---|---|---|---|---|---|
| string | string? | string? | string | string | string | string / Uint8Array | Set<string> | string? | Record<string, Set<string>>? |
| name (pk) | menu | reviews | stars |
|---|---|---|---|
| string | MenuItem[] | number | number |
| userID (pk) | timestamp (sk) | restaurantName | items | status |
|---|---|---|---|---|
| string | number | string | Stripe.LineItem[] | string |
- Clone the project and install dependencies with
pnpm installornpm install. - Create a .env file by copying and modifying .env.example
- Run
pnpm run devand visithttp://localhost:5173
This app is best deployed on serverless providers like Vercel, but it can also be run with node.js.
Read more here.
Copyright (C) 2022 Miika Tuominen
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program.