Skip to content

Commit 3d19868

Browse files
committed
init
0 parents  commit 3d19868

File tree

270 files changed

+34148
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

270 files changed

+34148
-0
lines changed

.cursor/rules/avoid-use-effect.mdc

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
---
2+
description:
3+
globs: *.tsx,*.jsx
4+
alwaysApply: false
5+
---
6+
### Avoid useEffect
7+
8+
[You Might Not Need `useEffect`](https://react.dev/learn/you-might-not-need-an-effect)
9+
10+
Instead of using `useEffect`, use ref callbacks, event handlers with
11+
`flushSync`, css, `useSyncExternalStore`, etc.
12+
13+
```tsx
14+
// This example was ripped from the docs:
15+
// ✅ Good
16+
function ProductPage({ product, addToCart }) {
17+
function buyProduct() {
18+
addToCart(product)
19+
showNotification(`Added ${product.name} to the shopping cart!`)
20+
}
21+
22+
function handleBuyClick() {
23+
buyProduct()
24+
}
25+
26+
function handleCheckoutClick() {
27+
buyProduct()
28+
navigateTo('/checkout')
29+
}
30+
// ...
31+
}
32+
33+
useEffect(() => {
34+
setCount(count + 1)
35+
}, [count])
36+
37+
// ❌ Avoid
38+
function ProductPage({ product, addToCart }) {
39+
useEffect(() => {
40+
if (product.isInCart) {
41+
showNotification(`Added ${product.name} to the shopping cart!`)
42+
}
43+
}, [product])
44+
45+
function handleBuyClick() {
46+
addToCart(product)
47+
}
48+
49+
function handleCheckoutClick() {
50+
addToCart(product)
51+
navigateTo('/checkout')
52+
}
53+
// ...
54+
}
55+
```
56+
57+
There are a lot more examples in the docs. `useEffect` is not banned or
58+
anything. There are just better ways to handle most cases.
59+
60+
Here's an example of a situation where `useEffect` is appropriate:
61+
62+
```tsx
63+
// ✅ Good
64+
useEffect(() => {
65+
const controller = new AbortController()
66+
67+
window.addEventListener(
68+
'keydown',
69+
(event: KeyboardEvent) => {
70+
if (event.key !== 'Escape') return
71+
72+
// do something based on escape key being pressed
73+
},
74+
{ signal: controller.signal },
75+
)
76+
77+
return () => {
78+
controller.abort()
79+
}
80+
}, [])
81+
```

.env.example

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
LITEFS_DIR="/litefs/data"
2+
DATABASE_PATH="./prisma/data.db"
3+
DATABASE_URL="file:./data.db?connection_limit=1"
4+
CACHE_DATABASE_PATH="./other/cache.db"
5+
SESSION_SECRET="super-duper-s3cret"
6+
HONEYPOT_SECRET="super-duper-s3cret"
7+
RESEND_API_KEY="re_blAh_blaHBlaHblahBLAhBlAh"
8+
SENTRY_DSN="your-dsn"
9+
10+
# this is set to a random value in the Dockerfile
11+
INTERNAL_COMMAND_TOKEN="some-made-up-token"
12+
13+
# the mocks and some code rely on these two being prefixed with "MOCK_"
14+
# if they aren't then the real github api will be attempted
15+
GITHUB_CLIENT_ID="MOCK_GITHUB_CLIENT_ID"
16+
GITHUB_CLIENT_SECRET="MOCK_GITHUB_CLIENT_SECRET"
17+
GITHUB_TOKEN="MOCK_GITHUB_TOKEN"
18+
GITHUB_REDIRECT_URI="https://example.com/auth/github/callback"
19+
20+
# set this to false to prevent search engines from indexing the website
21+
# default to allow indexing for seo safety
22+
ALLOW_INDEXING="true"
23+
24+
# Tigris Object Storage (S3-compatible) Configuration
25+
AWS_ACCESS_KEY_ID="mock-access-key"
26+
AWS_SECRET_ACCESS_KEY="mock-secret-key"
27+
AWS_REGION="auto"
28+
AWS_ENDPOINT_URL_S3="https://fly.storage.tigris.dev"
29+
BUCKET_NAME="mock-bucket"

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<!-- Summary: Put your summary here -->
2+
3+
## Test Plan
4+
5+
<!-- What steps need to be taken to verify this works as expected? -->
6+
7+
## Checklist
8+
9+
- [ ] Tests updated
10+
- [ ] Docs updated
11+
12+
## Screenshots
13+
14+
<!-- If what you're changing is within the app, please show before/after.
15+
You can provide a video as well if that makes more sense -->

.github/workflows/deploy.yml

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
name: 🚀 Deploy
2+
on:
3+
push:
4+
branches:
5+
- main
6+
- dev
7+
pull_request: {}
8+
9+
concurrency:
10+
group: ${{ github.workflow }}-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
permissions:
14+
actions: write
15+
contents: read
16+
17+
jobs:
18+
lint:
19+
name: ⬣ ESLint
20+
runs-on: ubuntu-22.04
21+
steps:
22+
- name: ⬇️ Checkout repo
23+
uses: actions/checkout@v4
24+
25+
- name: ⎔ Setup node
26+
uses: actions/setup-node@v4
27+
with:
28+
node-version: 22
29+
30+
- name: 📥 Download deps
31+
uses: bahmutov/npm-install@v1
32+
33+
- name: 🏄 Copy test env vars
34+
run: cp .env.example .env
35+
36+
- name: 🖼 Build icons
37+
run: npm run build:icons
38+
39+
- name: 🛠 Setup Database
40+
run: npx prisma migrate deploy && npx prisma generate --sql
41+
42+
- name: 🔬 Lint
43+
run: npm run lint
44+
45+
typecheck:
46+
name: ʦ TypeScript
47+
runs-on: ubuntu-22.04
48+
steps:
49+
- name: ⬇️ Checkout repo
50+
uses: actions/checkout@v4
51+
52+
- name: ⎔ Setup node
53+
uses: actions/setup-node@v4
54+
with:
55+
node-version: 22
56+
57+
- name: 📥 Download deps
58+
uses: bahmutov/npm-install@v1
59+
60+
- name: 🏄 Copy test env vars
61+
run: cp .env.example .env
62+
63+
- name: 🖼 Build icons
64+
run: npm run build:icons
65+
66+
- name: 🛠 Setup Database
67+
run: npx prisma migrate deploy && npx prisma generate --sql
68+
69+
- name: 🔎 Type check
70+
run: npm run typecheck --if-present
71+
72+
vitest:
73+
name: ⚡ Vitest
74+
runs-on: ubuntu-22.04
75+
steps:
76+
- name: ⬇️ Checkout repo
77+
uses: actions/checkout@v4
78+
79+
- name: ⎔ Setup node
80+
uses: actions/setup-node@v4
81+
with:
82+
node-version: 22
83+
84+
- name: 📥 Download deps
85+
uses: bahmutov/npm-install@v1
86+
87+
- name: 🏄 Copy test env vars
88+
run: cp .env.example .env
89+
90+
- name: 🖼 Build icons
91+
run: npm run build:icons
92+
93+
- name: 🛠 Setup Database
94+
run: npx prisma migrate deploy && npx prisma generate --sql
95+
96+
- name: ⚡ Run vitest
97+
run: npm run test -- --coverage
98+
99+
playwright:
100+
name: 🎭 Playwright
101+
runs-on: ubuntu-22.04
102+
timeout-minutes: 60
103+
steps:
104+
- name: ⬇️ Checkout repo
105+
uses: actions/checkout@v4
106+
107+
- name: 🏄 Copy test env vars
108+
run: cp .env.example .env
109+
110+
- name: ⎔ Setup node
111+
uses: actions/setup-node@v4
112+
with:
113+
node-version: 22
114+
115+
- name: 📥 Download deps
116+
uses: bahmutov/npm-install@v1
117+
118+
- name: 📥 Install Playwright Browsers
119+
run: npm run test:e2e:install
120+
121+
- name: 🛠 Setup Database
122+
run: npx prisma migrate deploy && npx prisma generate --sql
123+
124+
- name: 🏦 Cache Database
125+
id: db-cache
126+
uses: actions/cache@v4
127+
with:
128+
path: prisma/data.db
129+
key:
130+
db-cache-schema_${{ hashFiles('./prisma/schema.prisma')
131+
}}-migrations_${{ hashFiles('./prisma/migrations/*/migration.sql')
132+
}}
133+
134+
- name: 🌱 Seed Database
135+
if: steps.db-cache.outputs.cache-hit != 'true'
136+
run: npx prisma migrate reset --force
137+
138+
- name: 🏗 Build
139+
run: npm run build
140+
141+
- name: 🎭 Playwright tests
142+
run: npx playwright test
143+
144+
- name: 📊 Upload report
145+
uses: actions/upload-artifact@v4
146+
if: always()
147+
with:
148+
name: playwright-report
149+
path: playwright-report/
150+
retention-days: 30
151+
152+
deploy:
153+
name: 🚀 Deploy
154+
runs-on: ubuntu-22.04
155+
needs: [lint, typecheck, vitest, playwright]
156+
# only build/deploy branches on pushes
157+
if: ${{ github.event_name == 'push' }}
158+
159+
steps:
160+
- name: ⬇️ Checkout repo
161+
uses: actions/checkout@v4
162+
with:
163+
fetch-depth: '50'
164+
165+
- name: 👀 Read app name
166+
uses: SebRollen/toml-action@v1.2.0
167+
id: app_name
168+
with:
169+
file: 'fly.toml'
170+
field: 'app'
171+
172+
- name: 🎈 Setup Fly
173+
uses: superfly/flyctl-actions/setup-flyctl@1.5
174+
175+
- name: 🚀 Deploy Staging
176+
if: ${{ github.ref == 'refs/heads/dev' }}
177+
run:
178+
flyctl deploy --remote-only --build-arg COMMIT_SHA=${{ github.sha }}
179+
--app ${{ steps.app_name.outputs.value }}-staging
180+
env:
181+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}
182+
183+
- name: 🚀 Deploy Production
184+
if: ${{ github.ref == 'refs/heads/main' }}
185+
run:
186+
flyctl deploy --remote-only --build-arg COMMIT_SHA=${{ github.sha }}
187+
--build-secret SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}
188+
env:
189+
FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }}

.gitignore

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
node_modules
2+
.DS_store
3+
4+
/build
5+
/server-build
6+
.env
7+
.cache
8+
9+
/prisma/data.db
10+
/prisma/data.db-journal
11+
/tests/prisma
12+
13+
/test-results/
14+
/playwright-report/
15+
/playwright/.cache/
16+
/tests/fixtures/email/
17+
/tests/fixtures/uploaded/
18+
/tests/fixtures/openimg/
19+
/coverage
20+
21+
/other/cache.db
22+
23+
# Easy way to create temporary files/folders that won't accidentally be added to git
24+
*.local.*
25+
26+
# generated files
27+
/app/components/ui/icons
28+
.react-router/

.npmrc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
legacy-peer-deps=true
2+
registry=https://registry.npmjs.org/

.prettierignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
node_modules
2+
3+
/build
4+
/public/build
5+
/server-build
6+
.env
7+
8+
/test-results/
9+
/playwright-report/
10+
/playwright/.cache/
11+
/tests/fixtures/email/*.json
12+
/coverage
13+
/prisma/migrations
14+
15+
package-lock.json

0 commit comments

Comments
 (0)