Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand Down
15 changes: 11 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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. |
Expand Down Expand Up @@ -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

Expand All @@ -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.

Expand Down
163 changes: 163 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
@@ -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;
}
}
20 changes: 20 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
@@ -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 (
<html lang="en">
<body>{children}</body>
</html>
)
}
44 changes: 44 additions & 0 deletions app/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
export default function HomePage() {
return (
<main>
<section className="hero" aria-labelledby="hero-title">
<div className="hero__content">
<p className="eyebrow">Sidecause</p>
<h1 id="hero-title">Small acts can move a community forward.</h1>
<p className="hero__lede">
Sidecause will help neighbors find practical ways to contribute
their time, from a one-hour errand to a weekend project.
</p>
<p className="hero__note">
The community board is being built. Check back soon to browse
opportunities or share one of your own.
</p>
</div>
</section>

<section className="principles" aria-labelledby="principles-title">
<div className="section-heading">
<p className="eyebrow">How it works</p>
<h2 id="principles-title">A clear path from need to impact.</h2>
</div>
<ol className="principles__list">
<li>
<span aria-hidden="true">01</span>
<h3>Find a cause</h3>
<p>Browse opportunities that need a neighbor’s help.</p>
</li>
<li>
<span aria-hidden="true">02</span>
<h3>Make a commitment</h3>
<p>Claim one task at a time and know exactly what is needed.</p>
</li>
<li>
<span aria-hidden="true">03</span>
<h3>See it through</h3>
<p>Mark the work finished so the community can see progress.</p>
</li>
</ol>
</section>
</main>
)
}
61 changes: 61 additions & 0 deletions docs/decisions/ADR-001-authentication.md
Original file line number Diff line number Diff line change
@@ -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
Loading
Loading