diff --git a/apps/api/Dockerfile b/apps/api/Dockerfile index 9026478..a581eae 100644 --- a/apps/api/Dockerfile +++ b/apps/api/Dockerfile @@ -22,12 +22,9 @@ CMD ["pnpm", "--filter", "api", "dev"] # 4. build FROM base AS builder WORKDIR /app -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/api/package.json ./apps/api/ -COPY packages/shared/package.json ./packages/shared/ -COPY packages/db/package.json ./packages/db/ -RUN pnpm install --frozen-lockfile +COPY --from=deps /app/node_modules ./node_modules COPY . . +RUN pnpm install RUN pnpm --filter shared build RUN pnpm --filter db build RUN pnpm --filter api build diff --git a/apps/web/Dockerfile b/apps/web/Dockerfile index dc4d137..bc18ec1 100644 --- a/apps/web/Dockerfile +++ b/apps/web/Dockerfile @@ -21,11 +21,9 @@ CMD ["pnpm", "--filter", "web", "dev", "--host"] # 4. Build FROM base AS builder WORKDIR /app -COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./ -COPY apps/web/package.json ./apps/web/ -COPY packages/shared/package.json ./packages/shared/ -RUN pnpm install --frozen-lockfile +COPY --from=deps /app/node_modules ./node_modules COPY . . +RUN pnpm install ARG VITE_API_URL ENV VITE_API_URL=$VITE_API_URL RUN pnpm --filter shared build diff --git a/apps/web/src/components/NotFound.tsx b/apps/web/src/components/NotFound.tsx deleted file mode 100644 index be4219d..0000000 --- a/apps/web/src/components/NotFound.tsx +++ /dev/null @@ -1,43 +0,0 @@ -import { Link } from "@tanstack/react-router"; - -export default function NotFound() { - return ( -
-
-
-
-
- -
- - lost in translation - -
- -

- 4 - - 0 - - 4 -

- -

- This page doesn't exist. Maybe it never did - or maybe you{" "} - - just guessed wrong - - . -

- -
- - Back to home - -
-
- ); -} diff --git a/apps/web/src/components/RootError.tsx b/apps/web/src/components/RootError.tsx deleted file mode 100644 index e370317..0000000 --- a/apps/web/src/components/RootError.tsx +++ /dev/null @@ -1,56 +0,0 @@ -import { Link } from "@tanstack/react-router"; - -interface RootErrorProps { - error: Error; - reset: () => void; -} - -export default function RootError({ error, reset }: RootErrorProps) { - return ( -
-
-
-
-
- -
- - something went wrong - -
- -

- Unexpected{" "} - - error - -

- -

- Something crashed. This has been noted —{" "} - it's not you. -

- - {import.meta.env.DEV && ( -
-          {error.message}
-        
- )} - -
- - - Back to home - -
-
- ); -} diff --git a/apps/web/src/components/RouteError.tsx b/apps/web/src/components/RouteError.tsx deleted file mode 100644 index d068eb4..0000000 --- a/apps/web/src/components/RouteError.tsx +++ /dev/null @@ -1,49 +0,0 @@ -interface RouteErrorProps { - error: Error; - reset: () => void; -} - -export default function RouteError({ error, reset }: RouteErrorProps) { - return ( -
-
-
-
-
- -
- - something went wrong - -
- -

- This page{" "} - - crashed - -

- -

- Something went wrong loading this page.{" "} - Try again or - head back home. -

- - {import.meta.env.DEV && ( -
-          {error.message}
-        
- )} - -
- -
-
- ); -} diff --git a/apps/web/src/components/landing/Hero.tsx b/apps/web/src/components/landing/Hero.tsx index 81f7bba..6a6de87 100644 --- a/apps/web/src/components/landing/Hero.tsx +++ b/apps/web/src/components/landing/Hero.tsx @@ -7,8 +7,8 @@ const Hero = () => { return (
-
-
+
+
@@ -28,11 +28,9 @@ const Hero = () => {

- A word appears. You pick the translation. You score points. Then you - queue up a room and{" "} - - beat friends - {" "} + A word appears. You pick the translation. You score points. + Then you queue up a room and{" "} + beat friends{" "} in real time.

diff --git a/apps/web/src/routes/__root.tsx b/apps/web/src/routes/__root.tsx index c672ced..1dc4378 100644 --- a/apps/web/src/routes/__root.tsx +++ b/apps/web/src/routes/__root.tsx @@ -1,8 +1,6 @@ import { createRootRoute, Outlet } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import Navbar from "../components/navbar/NavBar"; -import NotFound from "../components/NotFound"; -import RootError from "../components/RootError"; const RootLayout = () => { return ( @@ -16,8 +14,4 @@ const RootLayout = () => { ); }; -export const Route = createRootRoute({ - component: RootLayout, - notFoundComponent: NotFound, - errorComponent: RootError, -}); +export const Route = createRootRoute({ component: RootLayout }); diff --git a/apps/web/src/routes/play.tsx b/apps/web/src/routes/play.tsx index df4959d..32db5c4 100644 --- a/apps/web/src/routes/play.tsx +++ b/apps/web/src/routes/play.tsx @@ -4,7 +4,6 @@ import type { GameSession, GameRequest, AnswerResult } from "@lila/shared"; import { QuestionCard } from "../components/game/QuestionCard"; import { ScoreScreen } from "../components/game/ScoreScreen"; import { GameSetup } from "../components/game/GameSetup"; -import RouteError from "../components/RouteError"; import { authClient } from "../lib/auth-client"; type GameStartResponse = { success: true; data: GameSession }; @@ -128,7 +127,6 @@ function Play() { export const Route = createFileRoute("/play")({ component: Play, - errorComponent: RouteError, beforeLoad: async () => { const { data: session } = await authClient.getSession(); if (!session) { diff --git a/documentation/backlog.md b/documentation/backlog.md index 865c9f2..127ee05 100644 --- a/documentation/backlog.md +++ b/documentation/backlog.md @@ -8,6 +8,12 @@ Labels: `[feature]` `[infra]` `[security]` `[ux]` `[debt]` Things that are actively in progress or should be picked up immediately. Mostly operational risk and the remaining phase 7 hardening work. +- **404 and redirect handling** `[ux]` + Unknown routes return raw errors. Add a catch-all route on the frontend for client-side 404s. Consider a Caddy fallback for unrecognized subdomains. + +- **React error boundaries** `[ux]` + Catch and display runtime errors gracefully instead of crashing the entire app. + - **Pin dependencies in package.json** `[debt]` `[infra]` Unpinned deps in a CI/CD pipeline are a real risk. Pin all versions to exact values to prevent unexpected breakage on build. @@ -23,6 +29,9 @@ Things that are actively in progress or should be picked up immediately. Mostly - **Conditionally register OAuth providers** `[debt]` Better Auth logs warnings when social providers are registered without credentials (`Social provider google is missing clientId or clientSecret`). Instead of registering all providers unconditionally, only add a provider to the config when its credentials are present in the environment. Keeps local dev clean for contributors who don't have OAuth apps set up. +- **Multiplayer GameService unit tests** `[debt]` + round evaluation, scoring, tie-breaking, timeout handling + --- ## next @@ -108,9 +117,6 @@ Directionally right, timing is unclear. Revisit when the next/now work is done. Shipped milestones, newest first. -- **04 - 2026 - React error boundaries** - Catch and display runtime errors gracefully instead of crashing the entire app. -- **04 - 2026 - 404 and redirect handling** - Unknown routes return raw errors. Add a catch-all route on the frontend for client-side 404s. -- **04 - 2026 - Multiplayer GameService unit tests** - round evaluation, scoring, tie-breaking, timeout handling - **04 - 2026 - Security headers with helmet** - Add helmet middleware to set secure HTTP response headers. - **04 - 2026 - Rate limiting on API endpoints** - At minimum: auth endpoints (brute force prevention) and game endpoints (spam prevention) - **04 - 2026 — Migrations in deploy pipeline** — Drizzle migrate runs as a CI/CD step before the API container restarts diff --git a/documentation/notes.md b/documentation/notes.md index eb25e7a..2da500d 100644 --- a/documentation/notes.md +++ b/documentation/notes.md @@ -1,19 +1,5 @@ # notes - -## prompt - -ive attached the readme of my project. this is my current task: - -task description. - -1. tell me which files you need to see to get the full context of the problem -2. walk me text-only through the problem and the solution -3. if we need to update multiple files: lets go through them one by one, no matter how many files -4. if we go through a file, we'll do it slowly section by section, no matter how many sections -5. how to name the current feature branch? also tell me when its time to git commit and provide a commit message -6. if we have multiple options to do something, also always provide options that reflect current industry standards and best practices - ## tasks - **IMPORTANT** db migrations have to be part of the deployment pipeline!!!!!!!!!!!!!!!!!!