diff --git a/AGENTS.md b/AGENTS.md index a1f944a..42b80ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,11 +2,12 @@ ## Project status -`infrastructure_plan.md` is the approved source of truth for the technical foundation. This repository now provides its planned local tooling, PostgreSQL/AIStor development services, Prisma migration setup, CI definitions, and smoke testing. It does not contain production application code. +`infrastructure_plan.md` is the approved source of truth for the technical foundation. The v1 product contract and its implementation sequence are in `docs/product-spec.md` and `docs/implementation-plan.md`. This repository provides local tooling, PostgreSQL/AIStor development services, Prisma migration setup, CI definitions, smoke testing, and the initial App Router shell. ## Repository map -- `app/` and `pages/`: Next.js front end/server code — not created yet. +- `app/`: Next.js App Router shell (`layout.tsx`, `page.tsx`, and global styles). +- `pages/`: unused; do not add Pages Router implementation. - `prisma/`: Prisma configuration and future migrations; no product models or migrations exist. - `tests/unit/`, `tests/integration/`, `tests/e2e/`: test locations; harness only. - `scripts/smoke.sh`: infrastructure-only service readiness test. @@ -40,11 +41,11 @@ npm run verify npm run test:smoke ``` -`npm run build`, `npm run test:integration`, and `npm run test:e2e` need future application code/tests and should not be made green with placeholders. CI currently omits those commands for this reason. +`npm run build` now verifies the App Router shell. `npm run test:integration` and `npm run test:e2e` need future application tests and should not be made green with placeholders. CI currently omits those application-test commands for this reason. ## Docker lifecycle -Start local services with `npm run docker:up` and stop them with `npm run docker:down`. This retains named volumes. The smoke test uses a separate Compose project and removes its volumes automatically. Run `docker compose down --volumes` only when intentionally resetting local PostgreSQL and AIStor data. The profile-gated `app` container requires a future Next.js entrypoint. +Start local services with `npm run docker:up` and stop them with `npm run docker:down`. This retains named volumes. The smoke test uses a separate Compose project and removes its volumes automatically. Run `docker compose down --volumes` only when intentionally resetting local PostgreSQL and AIStor data. Start the profile-gated application container with `docker compose --profile app up --build`. ## Change checklist diff --git a/README.md b/README.md index 3189a8e..de2afe5 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,14 @@ ## Status -This repository contains the development foundation for a public-facing Next.js application. Production application code, routes, authentication, database models, migrations, and browser workflows have **not** been created yet. The approved decisions are recorded in [infrastructure_plan.md](infrastructure_plan.md). +This repository contains the development foundation and initial App Router shell for a public-facing Next.js application. The root landing page, layout, and global styles are ready for feature development; authentication, database models, migrations, API routes, and browser workflows have **not** been created yet. The approved product decisions are recorded in [docs/product-spec.md](docs/product-spec.md) and [docs/implementation-plan.md](docs/implementation-plan.md). ## Repository map | Location | Purpose | | ------------------------------------------------- | ------------------------------------------------------------------------------- | -| `app/`, `pages/` | Planned Next.js UI and server features; not created yet. | +| `app/` | Next.js App Router shell: root layout, landing page, and global styles. | +| `pages/` | Unused; new application routes use the App Router only. | | `prisma/` | Prisma connection and migration configuration; no product schema or migrations. | | `tests/unit/`, `tests/integration/`, `tests/e2e/` | Planned test locations; currently empty harnesses. | | `scripts/smoke.sh` | Isolated PostgreSQL and AIStor infrastructure smoke test. | @@ -51,7 +52,13 @@ This repository contains the development foundation for a public-facing Next.js npm run docker:down ``` -`npm run dev`, `npm run build`, and `npm run test:e2e` are configured for the future Next.js application but cannot succeed until application code and browser tests exist. The `app` Compose profile is intentionally not started by default for the same reason. +Start the App Router shell locally with `npm run dev`, and create a production build with `npm run build`. `npm run test:e2e` remains deferred until browser workflows exist. The `app` Compose profile is intentionally not started by default; use `docker compose --profile app up --build` when you want to run the full local stack in containers. + +To install dependencies, start local services, and launch the development server in one command, run: + +```sh +./scripts/dev.sh +``` ## Database migrations @@ -65,7 +72,7 @@ Use `npm run prisma:deploy` only in a controlled deployment workflow against an ## CI and GitHub configuration -Pull requests run formatting, linting, TypeScript, the current Vitest coverage harness, Gitleaks, and CodeQL. The Next.js build, integration suite, and Playwright suite are deferred until application code exists. Configure branch protection to require those completed checks and a review. +Pull requests run formatting, linting, TypeScript, the current Vitest coverage harness, Gitleaks, and CodeQL. The Next.js build is now available locally; the integration suite and Playwright suite remain deferred until their workflows exist. Configure branch protection to require those completed checks and a review. Dependabot checks npm, Docker, and GitHub Actions dependencies weekly. Releases are intentionally blocked until a container registry and managed container host are selected. Before enabling release publishing/deployment, create a protected GitHub `production` environment and supply `CONTAINER_REGISTRY_TOKEN`, `CLOUD_DEPLOY_CREDENTIALS`, `DATABASE_URL`, `OBJECT_STORAGE_*`, and `AUTH_*` as environment-scoped secrets. diff --git a/app/globals.css b/app/globals.css new file mode 100644 index 0000000..f26b700 --- /dev/null +++ b/app/globals.css @@ -0,0 +1,163 @@ +:root { + color-scheme: light; + --canvas: #f7f4ed; + --ink: #20251f; + --muted: #5d675d; + --line: #cdd5c8; + --accent: #476a45; + --accent-soft: #dfe9d9; +} + +* { + box-sizing: border-box; +} + +html { + background: var(--canvas); +} + +body { + margin: 0; + color: var(--ink); + background: var(--canvas); + font-family: Arial, Helvetica, sans-serif; + font-size: 1rem; + line-height: 1.5; +} + +h1, +h2, +h3, +p { + margin: 0; +} + +.hero { + min-height: 66vh; + display: grid; + align-items: end; + padding: 3rem 1.5rem; + background: + linear-gradient(130deg, transparent 0 62%, rgb(225 182 117 / 44%) 62% 100%), + var(--accent-soft); +} + +.hero__content, +.principles { + width: min(100%, 70rem); + margin: 0 auto; +} + +.hero__content { + max-width: 49rem; +} + +.eyebrow { + color: var(--accent); + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +h1, +h2, +h3 { + font-family: Georgia, 'Times New Roman', serif; + font-weight: 500; + line-height: 1.08; +} + +h1 { + max-width: 12ch; + margin-top: 1rem; + font-size: clamp(3rem, 10vw, 6.5rem); +} + +.hero__lede { + max-width: 38rem; + margin-top: 1.5rem; + font-size: clamp(1.125rem, 2vw, 1.4rem); +} + +.hero__note { + max-width: 36rem; + margin-top: 1.25rem; + color: var(--muted); +} + +.principles { + padding: 4rem 1.5rem 5rem; +} + +.section-heading { + max-width: 35rem; +} + +h2 { + margin-top: 0.75rem; + font-size: clamp(2rem, 5vw, 3.5rem); +} + +.principles__list { + display: grid; + gap: 0; + margin: 3rem 0 0; + padding: 0; + list-style: none; + border-top: 1px solid var(--line); +} + +.principles__list li { + display: grid; + grid-template-columns: 3.5rem 1fr; + gap: 0.25rem 1rem; + padding: 1.5rem 0; + border-bottom: 1px solid var(--line); +} + +.principles__list span { + grid-row: span 2; + color: var(--accent); + font-size: 0.75rem; + font-weight: 700; + letter-spacing: 0.08em; +} + +h3 { + font-size: 1.35rem; +} + +.principles__list p { + color: var(--muted); +} + +@media (min-width: 48rem) { + .hero { + padding: 5rem 3rem; + } + + .principles { + padding: 5rem 3rem 6rem; + } + + .principles__list { + grid-template-columns: repeat(3, 1fr); + } + + .principles__list li { + grid-template-columns: 1fr; + gap: 0.75rem; + min-height: 14rem; + padding: 1.5rem 2rem 1.5rem 0; + } + + .principles__list li + li { + padding-left: 2rem; + border-left: 1px solid var(--line); + } + + .principles__list span { + grid-row: auto; + } +} diff --git a/app/layout.tsx b/app/layout.tsx new file mode 100644 index 0000000..52d30d6 --- /dev/null +++ b/app/layout.tsx @@ -0,0 +1,20 @@ +import type { Metadata } from 'next' +import type { ReactNode } from 'react' + +import './globals.css' + +export const metadata: Metadata = { + title: 'Sidecause | Community service, made practical', + description: + 'Find a community service opportunity, make a difference, and share what was completed.', +} + +export default function RootLayout({ + children, +}: Readonly<{ children: ReactNode }>) { + return ( + + {children} + + ) +} diff --git a/app/page.tsx b/app/page.tsx new file mode 100644 index 0000000..fec621a --- /dev/null +++ b/app/page.tsx @@ -0,0 +1,44 @@ +export default function HomePage() { + return ( +
+
+
+

Sidecause

+

Small acts can move a community forward.

+

+ Sidecause will help neighbors find practical ways to contribute + their time, from a one-hour errand to a weekend project. +

+

+ The community board is being built. Check back soon to browse + opportunities or share one of your own. +

+
+
+ +
+
+

How it works

+

A clear path from need to impact.

+
+
    +
  1. + +

    Find a cause

    +

    Browse opportunities that need a neighbor’s help.

    +
  2. +
  3. + +

    Make a commitment

    +

    Claim one task at a time and know exactly what is needed.

    +
  4. +
  5. + +

    See it through

    +

    Mark the work finished so the community can see progress.

    +
  6. +
+
+
+ ) +} diff --git a/docs/decisions/ADR-001-authentication.md b/docs/decisions/ADR-001-authentication.md new file mode 100644 index 0000000..3e43c48 --- /dev/null +++ b/docs/decisions/ADR-001-authentication.md @@ -0,0 +1,61 @@ +# ADR-001: Use Auth.js credentials with Prisma-backed local accounts + +## Status + +Accepted + +## Date + +2026-09-28 + +## Context + +Sidecause needs authenticated members to post, claim, finish, verify, and +cancel bounties. The application is a new Next.js 16 App Router project with +Prisma and PostgreSQL already selected for application data. The v1 product +scope requires email-and-password accounts, a public display name, no social +sign-in, no email verification, and no password recovery. + +## Decision + +Use Auth.js with a credentials-based sign-in flow and Prisma/PostgreSQL-backed +local user records. Store only a secure password hash; never expose the hash or +email address in public bounty responses. Server-side authorization uses the +authenticated local user ID. + +## Alternatives considered + +### Clerk + +Clerk has first-class Next.js support and a quick setup, but it adds a +vendor-managed identity layer and provider keys to a project that already owns +its relational data model. It is not needed for the intentionally small v1 +credentials flow. + +### Supabase Auth + +Supabase Auth integrates with Next.js, but adopting it would introduce a +separate hosted auth/PostgreSQL ecosystem alongside the project’s existing +Prisma-managed PostgreSQL direction. + +### Social sign-in + +Social sign-in reduces password management but is explicitly out of scope for +v1. + +## Consequences + +- The project owns its user identity relationships and authorization model. +- Credential validation, secure password hashing, session handling, and + rate-limiting are implementation responsibilities. +- No email provider is required for v1, but users cannot verify email addresses + or recover forgotten passwords. +- Adding password recovery or email verification later requires an email + provider and a reviewed security design. + +## Sources + +- https://authjs.dev/ +- https://authjs.dev/reference/core/errors#missingsecret +- https://clerk.com/docs/nextjs/getting-started/quickstart +- https://supabase.com/docs/guides/auth/quickstarts/nextjs diff --git a/docs/implementation-plan.md b/docs/implementation-plan.md new file mode 100644 index 0000000..6dca023 --- /dev/null +++ b/docs/implementation-plan.md @@ -0,0 +1,158 @@ +# Sidecause v1 Implementation Plan + +## Overview + +Implement Sidecause in small, testable vertical slices. The product contract in +[`product-spec.md`](product-spec.md) is the source of truth. Each schema and +API task must preserve the documented public/hidden status boundary and the +single-volunteer claim invariant. + +## Architecture decisions + +- Use the Next.js App Router; do not create parallel Pages Router features. +- Use Auth.js with email-and-password credentials and Prisma/PostgreSQL-backed + user records. Passwords are stored only as secure hashes. +- Expose REST-style route handlers with a single structured error shape. +- Use transactions or an equivalent guarded conditional update for claims. + +## Task list + +### Phase 1: Application and account foundation + +#### Task 1: Create the App Router shell + +**Acceptance criteria:** + +- [ ] The app has a root layout, public landing page, and global styles. +- [ ] `npm run dev`, linting, formatting, and type checking work. +- [ ] `pages/` has no application implementation. + +**Verify:** `npm run verify`; manually load the landing page. + +**Dependencies:** None. + +**Likely files:** `app/layout.tsx`, `app/page.tsx`, `app/globals.css`. + +#### Task 2: Add registration and session authentication + +**Acceptance criteria:** + +- [ ] A member can register with display name, unique email, and password. +- [ ] Passwords are securely hashed and never returned by application APIs. +- [ ] A member can sign in and sign out; visitors cannot perform mutations. + +**Verify:** Unit tests for credential validation and hashing; browser test for +registration and sign-in. + +**Dependencies:** Task 1; approval of the authentication dependency and first +Prisma migration. + +**Likely files:** `auth.ts`, `app/api/auth/[...nextauth]/route.ts`, +`proxy.ts`, `prisma/schema.prisma`, authentication pages and tests. + +### Checkpoint: accounts + +- [ ] A public page is accessible without a session. +- [ ] Protected mutation attempts return the documented `401` error. +- [ ] The migration is reviewed and no secrets are committed. + +### Phase 2: Publish and browse bounties + +#### Task 3: Define and migrate the bounty domain + +**Acceptance criteria:** + +- [ ] The schema represents locations, deadlines, lifecycle status, poster, + optional claimant, completion, verification, and cancellation reason. +- [ ] The schema makes a single claimant unambiguous and supports future + additive volunteer capacity. +- [ ] A migration is reviewed and applies to local PostgreSQL. + +**Verify:** `npm run prisma:validate`; run the reviewed development migration; +integration tests for persistence constraints. + +**Dependencies:** Task 2 and explicit approval for the migration. + +**Likely files:** `prisma/schema.prisma`, `prisma/migrations/*`, domain types, +integration tests. + +#### Task 4: Create and list public bounties + +**Acceptance criteria:** + +- [ ] An authenticated member can create a valid open bounty. +- [ ] Visitors can browse a paginated list of `OPEN`, `CLAIMED`, and + `FINISHED` bounties. +- [ ] Cancelled and expired bounties never appear in public list or detail + responses. + +**Verify:** Unit tests for input schemas and expiry calculation; integration +tests for API contracts; browser test for browse and create flows. + +**Dependencies:** Task 3. + +**Likely files:** bounty validation/domain service, route handlers, list/detail +pages and components, unit/integration/e2e tests. + +### Checkpoint: publishing and discovery + +- [ ] Public read paths work while signed out. +- [ ] Validation and authorization errors use the specified shape. +- [ ] `npm run verify` and relevant integration/browser tests pass. + +### Phase 3: Claim and completion lifecycle + +#### Task 5: Claim and withdraw safely + +**Acceptance criteria:** + +- [ ] Exactly one member can claim an open, unexpired bounty. +- [ ] A second or late claim returns `409` and does not modify ownership. +- [ ] The claimant can withdraw, returning the bounty to `OPEN`. + +**Verify:** Concurrent integration test for claim attempts; browser test for +claim and withdrawal. + +**Dependencies:** Task 4. + +**Likely files:** claim service, claim route handlers, bounty detail UI, tests. + +#### Task 6: Finish, verify, and cancel + +**Acceptance criteria:** + +- [ ] Only the claimant can finish a claimed bounty, without proof submission. +- [ ] Only the poster can optionally verify a finished bounty. +- [ ] Only the poster can cancel an open or claimed bounty with an optional + reason. + +**Verify:** Authorization and transition integration tests; browser test for +the full poster/claimant workflow. + +**Dependencies:** Task 5. + +**Likely files:** lifecycle service, route handlers, detail UI, tests. + +### Checkpoint: v1 completion + +- [ ] Each success criterion in the product spec passes via automated test or + documented manual check. +- [ ] `npm run verify`, `npm run test:smoke`, and relevant application tests + pass. +- [ ] Review the API contract, migration, and private-data exposure before + release planning. + +## Risks and mitigations + +| Risk | Impact | Mitigation | +| ------------------------------------ | ---------------------- | ---------------------------------------------------------------------------------------------------------- | +| Two members claim simultaneously | High | Use a transaction/conditional status update and test concurrent requests. | +| Unverified email plus no recovery | High user-support cost | Make the limitation explicit in registration UI; revisit verification/recovery before public launch. | +| Inappropriate or unsafe public posts | High | Moderation is intentionally deferred; do not launch broadly until a reporting/moderation decision is made. | +| Deadlines depend on client clocks | Medium | Compare deadlines on the server and use one UTC timestamp representation. | + +## Approval gates + +Before Task 2: approve the Auth.js credential implementation and its dependency +changes. Before Task 3: approve the User and Bounty Prisma migration. Before a +public launch: choose account recovery/verification and moderation policies. diff --git a/docs/product-spec.md b/docs/product-spec.md new file mode 100644 index 0000000..ebc658b --- /dev/null +++ b/docs/product-spec.md @@ -0,0 +1,156 @@ +# Sidecause v1 Product Specification + +## Objective + +Sidecause is a public community-service bounty board. Anyone can browse active +or completed opportunities. Signed-in members can post an opportunity, claim +one, and manage the resulting volunteer work. + +The first release is deliberately small: a bounty is a single-volunteer, +unpaid opportunity. It must make it easy to discover a project, commit to it, +and show that it was finished. + +## Users and access + +| User | Can do | +| ---------------- | ---------------------------------------------------------------------------------------- | +| Visitor | Browse `OPEN`, `CLAIMED`, and `FINISHED` bounties. | +| Signed-in member | All visitor actions plus create, claim, withdraw from, and finish bounties. | +| Bounty poster | All member actions plus cancel and optionally verify completion of bounties they posted. | + +Authentication uses an email address, password, and public display name. Email +verification, password recovery, social sign-in, and moderation are out of +scope for v1. A user who loses their password cannot recover the account in +v1. + +## Bounty lifecycle + +```text +OPEN --claim--> CLAIMED --finish--> FINISHED + ^ | + |---withdraw------| + +OPEN or CLAIMED --cancel--> CANCELLED +OPEN --deadline passes--> EXPIRED +``` + +- Only one member may claim an `OPEN` bounty. +- Finishing is immediate and requires no note, photograph, or poster approval. +- A poster may optionally verify a finished bounty. Verification is separate + from its status and never blocks finishing. +- A poster may cancel an `OPEN` or `CLAIMED` bounty, optionally supplying a + cancellation reason. +- Published bounties cannot otherwise be edited. +- Public listings and public detail pages expose only `OPEN`, `CLAIMED`, and + `FINISHED` bounties. `CANCELLED` and `EXPIRED` bounties are not public. +- Expiry is determined server-side from the deadline. An expired bounty cannot + be claimed. + +## Bounty data + +Each bounty has: + +- A required title and description. +- A required human-readable location label, such as a neighbourhood or a + specific address. +- Optional precise latitude and longitude, supplied together when the location + is specific enough for a map point. +- A required deadline. A bounty expires after it. +- The poster, optional claimant, status, creation time, finish time, optional + verification time, and optional cancellation reason. + +Display names are public where a poster or claimant is shown. Email addresses, +password hashes, and authentication/session data are never public. + +## Application boundary and API contract + +Use the Next.js App Router only; `pages/` remains unused. Public reads remain +available without a session. Every mutation requires an authenticated session +and performs authorization on the server. + +All API errors use this response shape: + +```json +{ + "error": { + "code": "VALIDATION_ERROR", + "message": "A deadline is required.", + "details": {} + } +} +``` + +Validation failures return `422`; unauthenticated requests `401`; unauthorized +requests `403`; missing or non-public resources `404`; and lifecycle conflicts +(such as a second simultaneous claim) `409`. Internal errors never reveal +implementation details. + +| Operation | Contract | +| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `GET /api/bounties` | Public, paginated list of public statuses. Supports `page`, `pageSize`, `status`, and location filtering defined during implementation. Returns `{ data, pagination }`. | +| `POST /api/bounties` | Authenticated creation. Accepts title, description, location, optional coordinates, and deadline. Returns the created bounty with `201`. | +| `GET /api/bounties/:id` | Public only for a public-status bounty; otherwise returns `404`. | +| `POST /api/bounties/:id/claims` | Authenticated. Atomically claims an open, unexpired bounty for the current user. | +| `DELETE /api/bounties/:id/claims/me` | Claimant only. Releases the claim and returns the bounty to `OPEN`. | +| `POST /api/bounties/:id/completion` | Claimant only. Marks the bounty `FINISHED`. | +| `POST /api/bounties/:id/verification` | Poster only. Marks a finished bounty verified. | +| `POST /api/bounties/:id/cancellation` | Poster only. Cancels an open or claimed bounty; body may include `reason`. | + +Inputs are validated at route-handler boundaries. Internal services receive +trusted, typed inputs. State-changing operations must be transactional so two +users cannot both claim the same bounty. + +## Commands + +```sh +npm ci +npm run docker:up +npm run dev +npm run verify +npm run test:smoke +``` + +Once application tests exist, use `npm run test:integration` and `npm run +test:e2e` for relevant changes. Do not add placeholder tests merely to make +those commands pass. + +## Project structure + +```text +app/ App Router pages, layouts, and route handlers +prisma/ Prisma schema and reviewed migrations +tests/unit/ Pure domain and validation tests +tests/integration/ PostgreSQL-backed route and persistence tests +tests/e2e/ Browser tests for public browsing and member workflows +docs/ Product specification, decisions, and implementation plans +``` + +## Boundaries + +- Always: validate external input at API boundaries, enforce authorization on + the server, run relevant tests, and keep user data account-scoped. +- Ask first: add dependencies, create or modify Prisma migrations, change + authentication providers, alter API contracts, or enable payments, XP, + uploads, moderation, email verification, or recovery. +- Never: expose private user data, trust client-supplied ownership or status, + commit credentials, or make cancelled/expired bounties public. + +## Success criteria + +- A visitor can view a paginated public list and public detail pages for open, + claimed, and finished bounties. +- A member can register, sign in, create a bounty, and claim one open bounty. +- A claimant can withdraw or finish their own claim; concurrent claims do not + assign two volunteers. +- A poster can cancel their own open or claimed bounty and optionally verify a + finished one. +- All invalid or unauthorized requests follow the documented error contract. + +## Explicitly deferred + +- Payments and experience-point rewards. +- Multiple volunteers per bounty. A future additive `volunteerCapacity` field + may extend the one-volunteer model. +- Bounty editing, proof uploads, comments, reporting, and moderation. +- Email verification, password recovery, social sign-in, and organization + accounts. diff --git a/next-env.d.ts b/next-env.d.ts new file mode 100644 index 0000000..304d663 --- /dev/null +++ b/next-env.d.ts @@ -0,0 +1,8 @@ +/// +/// +/// +import './.next/dev/types/routes.d.ts' +import './.next/dev/types/root-params.d.ts' + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/next.config.ts b/next.config.ts new file mode 100644 index 0000000..189c05a --- /dev/null +++ b/next.config.ts @@ -0,0 +1,11 @@ +import type { NextConfig } from 'next' +import { fileURLToPath } from 'node:url' + +const nextConfig: NextConfig = { + agentRules: false, + turbopack: { + root: fileURLToPath(new URL('.', import.meta.url)), + }, +} + +export default nextConfig diff --git a/scripts/dev.sh b/scripts/dev.sh new file mode 100755 index 0000000..fc89d0e --- /dev/null +++ b/scripts/dev.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +set -euo pipefail + +project_root="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +cd "$project_root" + +npm ci +npm run docker:up +exec npm run dev +npm run docker:down \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index a9f4f0c..838ba39 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,10 +10,21 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, - "jsx": "preserve", + "jsx": "react-jsx", "incremental": true, - "plugins": [{ "name": "next" }] + "plugins": [ + { + "name": "next" + } + ], + "esModuleInterop": true }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "include": [ + "next-env.d.ts", + "**/*.ts", + "**/*.tsx", + ".next/types/**/*.ts", + ".next/dev/types/**/*.ts" + ], "exclude": ["node_modules"] }