| Home |
|---|
![]() |
pnpm install
npm run devMake sure to check .env.example to check the necessary variables needed to run the probject.
To run with mocked data make sure to the the .env variable USE_MOCKS=true.
Keep in mind that this will make PAYLOAD_GRAPHQL_URL to be ignored and some other endpoints are fake.
To setup more fake responses:
- If the request is for nuxt backend, handle it in
01.mock.ts - If it's an external API call, mock it in
mocks/handlers/index.ts
To disable only the external mock, comment this part in 02.initializer.client
if (isStringTrue(useMocks)) {
const { worker } = useSetupMSWWorker();
worker.start({ onUnhandledRequest: 'bypass' });
}The songs audio files are not mocked but they are cached on indexedDB through localforage so if you need a new song to be added, update the metadata mocks and run once without the mocked data. Once the audio is loaded once you can add the mocks back.
This project is my experimental playground where I try out different things, so the structure and coding may not be as organized as you would expect in a real project.
In real life, we don't usually use so many different animations and implement the same thing in different ways. But here, I went all out and did everything I've always wanted to do!
The main focus here is on three things:
- the amount of maintenance required in the code (this project is not meant to be constantly changed);
- the number of developers working on the code (just me), and;
- concentrating on what truly matters (perfectionism isn't always necessary).
If you're interested in checking out some well-structured code, take a look at my github and the js-libs project where I create helper functions for my projects.
Using only i18n route logic to control the language was a little bit bad for experience because I didn't wanted the user to go back to the start of the page everytime the language changes. So what I did was to use a combination of both query and path parameters. The query parameters takes precedence if defined.
The URL might end up very weird as /pt-BR (being translated to english) or /?locale=pt-BR being translate but I prefered that beacuse I could take the benefits of both approaches. Using the path route I'm able to generate the SSR version of the website for all routes and using the query parameter I can refresh the page without scrolling top.
For reidrect rules to work, your endpoints must be with proxy enabled
- Make sure to add
NITRO_PRESET=cloudflare_pageson .env - run
npx nuxt build && npx wrangler pages dev dist
-
If you run the app in a small screen theres a hydration missmatch warning in the console because the generated pages uses the desktop header that don't appear in small screens. I guess it's not a bug but it's worth mentioning that it's normal to happen.
-
Pinia do not support Hot Reload out of the box and for adding it I would need to update the sintax of the stores and some of the logic to the "Options API" style, which I don't think is worth the effort. For further investigation, checks: https://pinia.vuejs.org/cookbook/hot-module-replacement.html#hmr-hot-module-replacement
If you want to work with mocks enable the environment variable USE_MOCKS=true.
To add more mocked endpoints check the 01.mock.ts server middleware and add new urls to the map.
-
Configure client portal: Settings -> Billing -> Customer Portal
- On Business Information: add redirect link to
http://localhost:3000/profilein test and tohttps://leonardorick.com/profilein production - On Subscriptions: Enable "Customers can swith plan"
- To test customer portal:
stripe billing_portal sessions create --customer cus_123456789
- On Business Information: add redirect link to
-
Configure payment link: Payments -> Payment Links -> Edit/Create -> After payment
- Select Don't show confirmation page
- Fill the input with
http://localhost:3000/login?stripe_checkout_id={CHECKOUT_SESSION_ID} - Now under Settings -> Payments -> Checkouts and Payment Links
- On the Subscriptions section enable "Limit customers to 1 subscription"
- Obs: Currently I couldn't find a way to allow the user to select the currency so we leave it to stripe to get his location and offer the better currency out of the box.
-
Configure subscriptions webhook: Developers -> Webhooks:
- Endpoint URL:
https://staging.leonardorick.com/api/stripeSubscriptionsWebhook - Events to send:
invoice.payment_succeeded
- Endpoint URL:
-
In Staging the Stripe Customer Portal and Payment links environment variables are not set/disabled so we don't allow the user to create Stripe subscriptions in staging.
- Setup stripe cli
- Create local listener
stripe loginstripe listen --forward-to localhost:3000/api/stripeSubscriptionsWebhook
- Go to the payments link, fill email and card and perform a payment.
- In stripe Dashboard go to the Developers --> Events.
- Find your event
invoice.payment_succeeded(theres usually two for payment:invoice.paidandinvoice.payment_succeeded) - Scroll down and find CLI answers with webhook

- Copy the body of the payload and paste on postman
- Tweak your server to answer what you want and to develop the webhook
- users collection:
- index_email: to find if user already exists before creating again
- allowed-emails:
- index_email: to check if user is on allowed-emails on both login and signup
- previews:
- index_number: to query previews based on number instead of fileId
- covers:
- index_number: to query covers based on the number instead of fileId
- Delete from stripe
- Delete all users sessions in Auth -> User -> Sessions
- Delete from users Auth
- Delete from users Collection
- Delete from allowed-email collection
- Upload the file in the storage
- Create the item in the previews collection
- Add the number in the settings collection (previewsReady)
- Create the document in the upvotes collection where the document ID is the preview number
- Optional: Update any user with the number in the availablePreviews if you want
- There's no array type so you select the type you wwant and them select if you want this to be an array.
- If you create an array there's no functionalitty on making it required because the default is always an empty array: https://discord.com/channels/564160730845151244/1090006380301275187
In appwrite we can't block single properties in a collection to be updated so we just block all updates to the user database to avoid allowing the user to update itself wrongly. In this collection and in many others you should use the relative nuxt endpoint (created by us) that deals with updating the collection.
