# Project export: Airline Said No

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Received an airline compensation claim refusal? Airline Said No explains the decision, highlights missing evidence, and helps you prepare a grounded, editable reply.
- Devpost: https://devpost.com/software/airline-said-no
- GitHub: https://github.com/MinervaRose/airline-said-no
- Video: https://www.youtube.com/embed/RR64KEt8Miw?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — MinervaRose (13 commits)

## Devpost submission (written by the team)

### Overview

Airline Said No Every year, thousands of travellers receive airline compensation refusals that are difficult to interpret. The response often contains legal terminology or generic statements such as "extraordinary circumstances" without explaining what actually happened or whether there is enough information to justify the decision. I wanted to build something that helps people understand these letters before deciding what to do next. Rather than acting as a legal advisor or trying to predict whether someone will win a claim, Airline Said No provides an explainable second opinion. It reconstructs the facts, explains the airline's reasoning in plain language, highlights missing or contradictory evidence, and suggests one realistic next step. One design principle guided the entire project: Facts → Interpretation → Recommendation The application never jumps directly to conclusions. It first establishes what can actually be confirmed from the evidence, then explains what those facts appear to mean, and only afterwards recommends a course of action. If the traveller wishes to continue, GPT-5.6 generates a calm, grounded reply based on the validated analysis rather than re-analysing the original document. The draft is fully editable and nothing is ever sent automatically, ensuring the user remains in control. How I built it The application was built with Next.js 16, React 19, TypeScript, and Tailwind CSS. GPT-5.6 powers two distinct stages of the experience: structured document analysis; grounded draft generation. Users can either paste the text of a rejection or upload a PDF, PNG, JPG, or JPEG document. Uploaded files remain request-scoped and are processed only for the current request. Throughout development I worked closely with Codex, which helped me move from an initial product concept to a production-ready application. Codex accelerated implementation, testing, accessibility improvements, refactoring, production hardening, and documentation, while I remained responsible for the product vision, interaction design, UX decisions, and iterative refinement. Challenges One of the biggest challenges was resisting the temptation to make the application overly confident. Early on I realised that simply generating persuasive replies was not enough. The application needed to distinguish between confirmed facts, passenger claims, airline assertions, and genuinely missing information. Another challenge was keeping the interface approachable despite analysing documents that may contain legal terminology. Captain WorthATry was introduced to make the experience feel friendly without distracting from the seriousness of the analysis. What I learned This project reinforced something I find particularly exciting about modern AI systems. Large language models are most useful when they help people reason more clearly rather than replacing their judgement. Building Airline Said No also showed me how powerful the collaboration between a human product designer, Codex, and GPT-5.6 can be. By combining structured reasoning with careful UX design, it became possible to build an application that is both technically capable and reassuring to use.

## README (from the GitHub repository)

<p align="center">
<img src="docs/images/hero-banner.png" alt="Airline Said No">
</p>

<h1 align="center">✈️ Airline Said No</h1>

<p align="center">
An explainable second opinion for airline compensation refusals.
<br>
Built collaboratively with <strong>Codex</strong> and <strong>GPT-5.6</strong> for OpenAI Build Week 2026.
</p>

<p align="center">

![Next.js](https://img.shields.io/badge/Next.js-16-black?logo=next.js)
![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=white)
![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white)
![Tailwind CSS](https://img.shields.io/badge/Tailwind_CSS-4-38B2AC?logo=tailwind-css&logoColor=white)
![OpenAI](https://img.shields.io/badge/OpenAI-GPT--5.6-412991)
![Tests](https://img.shields.io/badge/Tests-78_Passing-success)
![License](https://img.shields.io/badge/License-MIT-green)

</p>

---

# What is Airline Said No?

We've all been there.

You receive an email explaining that your compensation claim has been rejected. The explanation is often brief, sometimes vague, and it's not always clear whether the decision is justified or worth challenging.

**Airline Said No** doesn't promise compensation, and it doesn't replace legal advice.

Instead, it helps travellers understand what actually happened by reconstructing the facts, explaining the airline's reasoning, highlighting missing or contradictory information, and suggesting one realistic next step.

If appropriate, it can then draft a calm, editable reply that the traveller remains completely free to modify before sending.

Every analysis follows the same order:

1. Facts
2. Interpretation
3. Recommendation

---

# Built with Codex & GPT-5.6

Airline Said No was developed collaboratively with **Codex** and **GPT-5.6** throughout OpenAI Build Week.

## GPT-5.6

GPT-5.6 powers the core intelligence of the application by:

- extracting structured facts from airline correspondence;
- distinguishing confirmed facts from uncertainty;
- identifying missing or contradictory evidence;
- generating explainable recommendations;
- drafting calm, grounded, fully editable replies.

## Codex

Rather than treating Codex as a code generator, I used it as an engineering partner throughout the project.

Codex helped me:

- design the application architecture;
- implement the Next.js application;
- refine prompts and interaction flows;
- improve accessibility and keyboard support;
- harden privacy and security;
- write and expand automated tests;
- review production readiness;
- prepare deployment;
- improve documentation and developer experience.

While Codex accelerated implementation, I remained responsible for the product vision, interaction design, user experience, prompt direction, and iterative refinement.

---

# Gallery

| Landing page | Analysis | Draft reply |
|--------------|----------|-------------|
| ![](docs/images/landing.png) | ![](docs/images/analysis.png) | ![](docs/images/draft.png) |

---

# 🎬 Demo Video

Watch a short demonstration of **Airline Said No** in action.

[![Watch the demo](docs/images/hero-banner.png)](https://youtu.be/RR64KEt8Miw)

▶️ https://youtu.be/RR64KEt8Miw

---

# Features

- ✈️ Explain airline compensation refusals in plain language
- 📄 Analyse PDF, PNG, JPG/JPEG and pasted text
- 🧠 Structured reasoning powered by GPT-5.6
- 🔍 Separate confirmed facts from uncertainty
- ⚠️ Highlight missing and contradictory evidence
- ✉️ Draft a professional, fully editable follow-up reply
- 🔒 Privacy-first request-scoped document processing

---

# Trying it yourself

## Requirements

- Node.js 22.x
- npm
- Your own OpenAI API key

Clone the repository, copy `.env.example` to `.env.local`, add your API key, then run:

```bash
npm install
npm run dev
```

The application will be available at:

```text
http://localhost:3000
```

---

## Sample documents

The `samples/` folder contains fictional airline correspondence designed to exercise different reasoning paths.

Included scenarios cover:

- potentially compensable delays;
- extraordinary circumstances;
- non-EU261 journeys;
- weak claims;
- contradictory information.

All sample documents were created specifically for this project. No real passenger data is included.

---

# Environment variables

| Variable | Required | Description |
|----------|----------|-------------|
| `OPENAI_API_KEY` | ✅ | Your OpenAI API key. Never exposed to the browser. |
| `OPENAI_MODEL` | Optional | Defaults to `gpt-5.6`. |

---

# Available scripts

| Command | Description |
|---------|-------------|
| `npm run dev` | Start the development server |
| `npm run build` | Create a production build |
| `npm run start` | Run the production build locally |
| `npm test` | Run the automated test suite |
| `npm run test:watch` | Watch mode |
| `npm run lint` | ESLint |
| `npm run typecheck` | Strict TypeScript |
| `npm run format` | Format files |
| `npm run format:check` | Check formatting |
| `npm run check` | Run formatting, linting and type checking |

---

# Project structure

```text
src/
├── app/
├── components/
│   ├── mascot/
│   └── ui/
├── config/
├── features/
└── styles/

samples/
docs/
```

---

# Architecture

Key engineering decisions include:

- Next.js App Router
- Server Components by default
- OpenAI Responses API
- Structured Outputs with Zod validation
- Request-scoped document processing
- No document persistence
- `store: false` on OpenAI requests
- Strict TypeScript
- Comprehensive automated testing
- Accessibility-first interface
- Keyboard navigation
- Reduced-motion support

---

# Deployment

The application is ready for deployment on Vercel.

For this Build Week submission it is intentionally demonstrated locally, allowing judges to use their own OpenAI API key when running the project.

Everything required for deployment is already included in the repository.

---

# Acknowledgements

Created for **OpenAI Build Week 2026** with **Codex** and **GPT-5.6**.

Special thanks to **Captain WorthATry** for flying through an alarming amount of paperwork.

## Detected evidence (automated analysis)

Indexed codebase: 71 recognized source files, 146 KB.
- CSS (language) — detected in the code
- Next.js (technology) — detected in the code
- OpenAI (technology) — detected in the code
- React (technology) — detected in the code
- Tailwind CSS (technology) — detected in the code
- TypeScript (language) — detected in the code
- Node.js (technology) — claimed on Devpost, not found in the code
- Vercel (technology) — claimed on Devpost, not found in the code
- AI coding agent: Claude Code — evidence: config files committed to the repository
- AI coding agent: Codex — evidence: config files committed to the repository

## Codebase structure (from repository index)

### Files (81 of 81)

```
.env.example
.gitignore
.prettierignore
.prettierrc.json
AGENTS.md
CLAUDE.md
eslint.config.mjs
LICENSE
next.config.ts
package.json
postcss.config.mjs
README.md
samples/northstar-email-01.txt
samples/README.md
src/app/api/analyze/route.ts
src/app/api/draft/route.ts
src/app/globals.css
src/app/layout.tsx
src/app/page.module.css
src/app/page.tsx
src/components/mascot/captain-worthatry.module.css
src/components/mascot/captain-worthatry.tsx
src/components/mascot/index.ts
src/components/ui/button.module.css
src/components/ui/button.tsx
src/components/ui/card.module.css
src/components/ui/card.tsx
src/components/ui/class-names.ts
src/components/ui/form-field.module.css
src/components/ui/form-field.tsx
src/components/ui/index.ts
src/components/ui/layout.module.css
src/components/ui/layout.tsx
src/components/ui/status-indicator.module.css
src/components/ui/status-indicator.tsx
src/components/ui/typography.module.css
src/components/ui/typography.tsx
src/config/env.ts
src/config/uploads.ts
src/features/analysis-journey/analysis-journey.module.css
src/features/analysis-journey/analysis-journey.test.tsx
src/features/analysis-journey/analysis-journey.tsx
src/features/analysis-journey/analysis-results.module.css
src/features/analysis-journey/analysis-results.test.tsx
src/features/analysis-journey/analysis-results.tsx
src/features/analysis-journey/index.ts
src/features/analysis-journey/investigation.module.css
src/features/analysis-journey/investigation.test.tsx
src/features/analysis-journey/investigation.tsx
src/features/analysis/engine.test.ts
src/features/analysis/engine.ts
src/features/analysis/index.ts
src/features/analysis/input.test.ts
src/features/analysis/input.ts
src/features/analysis/openai-provider.ts
src/features/analysis/prompt.test.ts
src/features/analysis/prompt.ts
src/features/analysis/schema.test.ts
src/features/analysis/schema.ts
src/features/draft-reply/draft-reply.module.css
src/features/draft-reply/draft-reply.test.tsx
src/features/draft-reply/draft-reply.tsx
src/features/draft-reply/index.ts
src/features/draft/engine.test.ts
src/features/draft/engine.ts
src/features/draft/index.ts
src/features/draft/openai-provider.ts
src/features/draft/prompt.test.ts
src/features/draft/prompt.ts
src/features/draft/schema.test.ts
src/features/draft/schema.ts
src/features/rejection-input/index.ts
src/features/rejection-input/rejection-input.module.css
src/features/rejection-input/rejection-input.test.tsx
src/features/rejection-input/rejection-input.tsx
src/features/rejection-input/validation.test.ts
src/features/rejection-input/validation.ts
src/styles/tokens.css
src/test/setup.ts
tsconfig.json
vitest.config.ts
```

### Dependencies

- package.json: @fontsource-variable/inter@^5.2.8, @fontsource-variable/space-grotesk@^5.2.10, @tailwindcss/postcss@^4, @testing-library/jest-dom@^6.9.1, @testing-library/react@^16.3.2, @testing-library/user-event@^14.6.1, @types/node@^20, @types/react@^19, @types/react-dom@^19, eslint@^9, eslint-config-next@16.2.10, eslint-config-prettier@^10.1.8, jsdom@^29.1.1, next@16.2.10, openai@^6.46.0, prettier@^3.9.5, react@19.2.4, react-dom@19.2.4, server-only@^0.0.1, tailwindcss@^4, typescript@^5, vitest@^4.1.10, zod@^4.4.3

### Recent commits (newest first)

- Create LICENSE
- docs: add details about Codex and GPT-5.6
- docs: add demo video link to README
- docs: polish README with screenshots and demo samples
- chore: finalize Vercel deployment readiness
- fix: harden product for production deployment
- feat: complete editable appeal journey
- feat: complete explainable analysis journey
- feat: deliver private structured EU261 analysis
- feat: landing page + complete input experience
- feat: add Captain WorthATry pixel art
- feat: establish visual design system
- chore: initialize production Next.js foundation

## Key source files (fetched from GitHub, selected and truncated for size)

### CLAUDE.md

```markdown
@AGENTS.md

```

### AGENTS.md

```markdown
<!-- BEGIN:nextjs-agent-rules -->

# This is NOT the Next.js you know

This version has breaking changes — APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` before writing any code. Heed deprecation notices.
<!-- END:nextjs-agent-rules -->

```

### package.json

```
{
  "name": "airline-said-no",
  "version": "0.1.0",
  "private": true,
  "engines": {
    "node": "22.x"
  },
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "test": "vitest run",
    "test:watch": "vitest",
    "lint": "eslint . --max-warnings=0",
    "typecheck": "tsc --noEmit",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "check": "npm run format:check && npm run lint && npm run typecheck"
  },
  "dependencies": {
    "@fontsource-variable/inter": "^5.2.8",
    "@fontsource-variable/space-grotesk": "^5.2.10",
    "next": "16.2.10",
    "openai": "^6.46.0",
    "react": "19.2.4",
    "react-dom": "19.2.4",
    "server-only": "^0.0.1",
    "zod": "^4.4.3"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@testing-library/jest-dom": "^6.9.1",
    "@testing-library/react": "^16.3.2",
    "@testing-library/user-event": "^14.6.1",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "16.2.10",
    "eslint-config-prettier": "^10.1.8",
    "jsdom": "^29.1.1",
    "prettier": "^3.9.5",
    "tailwindcss": "^4",
    "typescript": "^5",
    "vitest": "^4.1.10"
  }
}

```

### src/app/page.tsx

```typescript
import { AnalysisJourney } from "@/features/analysis-journey";

export default function Home() {
  return <AnalysisJourney />;
}

```

### src/app/layout.tsx

```typescript
import type { Metadata } from "next";

import "./globals.css";

export const metadata: Metadata = {
  title: "Airline Said No",
  description: "An explainable second opinion on airline refusals.",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}

```

### src/features/draft-reply/index.ts

```typescript
export { DraftReply } from "./draft-reply";

```

### src/features/analysis-journey/index.ts

```typescript
export { AnalysisJourney } from "./analysis-journey";

```

### src/components/mascot/index.ts

```typescript
export {
  CaptainWorthATry,
  type CaptainWorthATryProps,
} from "./captain-worthatry";

```

### src/features/draft/index.ts

```typescript
export { generateDraft } from "./engine";
export type { DraftProvider } from "./engine";
export { draftRequestSchema, draftSchema } from "./schema";
export type { Draft } from "./schema";

```

### src/features/rejection-input/index.ts

```typescript
export { RejectionInput } from "./rejection-input";
export type { RejectionSubmission } from "./rejection-input";
export {
  MAX_FILE_SIZE_BYTES,
  formatFileSize,
  validateFiles,
  validatePastedText,
} from "./validation";

```

[60 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]