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
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ node_modules/
.env.test.local
.env.production.local

# Local Copilot helper folders
.github/instructions/
.github/prompts/
.github/chatmodes/

# Logs
npm-debug.log*
yarn-debug.log*
Expand Down Expand Up @@ -56,3 +61,4 @@ temp/
# Supabase
.branches
.temp
repomix-output.xml
149 changes: 100 additions & 49 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,82 +1,133 @@
# Mindley App
# Mindley

A full-stack application built with React/TypeScript frontend and Supabase
backend.
<img src="frontend/public/mindley-icon.svg" alt="Mindley logo" width="120" style="height:auto;" />

## Project Structure
A small productivity and knowledge-sharing platform with a React + TypeScript frontend and a Supabase backend (Edge Functions written for Deno).

> [!NOTE]
> This README is a concise developer-focused reference. For detailed API docs or deployment runbooks check the `supabase/` folder and the `frontend/README.md`.

## Quick overview

- Frontend: React + TypeScript, Vite, Tailwind CSS.
- Backend: Supabase project with Deno-based Edge Functions in `supabase/functions/`.
- Local dev: Frontend runs with `npm run dev` (in `frontend/`); Supabase functions use the Supabase CLI for local serving.

## Key features

- Resource listing and detail pages
- Authentication (OTP sign-in flow) using Supabase
- Background job monitoring via Supabase Functions
- Small component library and UI primitives in `src/components/ui`

## Repository layout

```
├── frontend/ # React/TypeScript frontend (deployed via Vercel)
├── supabase/ # Supabase backend and Edge Functions
│ └── functions/ # Deno-based Edge Functions
└── .github/workflows/ # CI/CD pipelines
frontend/ # React app (Vite + TypeScript)
public/ # static assets (icons, manifest)
src/ # source code (components, pages, hooks, services)
supabase/ # Supabase project and Edge Functions (Deno)
functions/ # serverless functions (create-resource, jobs, etc.)
package.json # workspace-level scripts and tooling (if present)
README.md # this file
```

## CI/CD Pipeline
## Getting started (local)

### Continuous Integration
Prerequisites:

The CI pipeline runs on every push and pull request to `main` and `develop`
branches. It includes:
- Node 18+ (or project-compatible runtime)
- npm or pnpm
- Supabase CLI (for local testing of functions)

#### Frontend CI
1. Frontend

- **Dependencies**: Installs npm packages with caching
- **Type Checking**: Validates TypeScript types with `tsc --noEmit`
- **Linting**: Runs ESLint to check code quality
- **Build**: Verifies the project builds successfully
```bash
cd frontend
npm install
npm run dev
```

#### Supabase Functions CI
Visit http://localhost:5173 (or the address printed by Vite).

- **Syntax Check**: Validates Deno/TypeScript syntax for all Edge Functions
- **Format Check**: Ensures consistent code formatting with `deno fmt`
2. Supabase functions (local)

#### Security Scanning
```bash
# from repo root or inside the supabase directory
supabase login # one-time, if not already logged in
supabase start # optional local DB + emulators
supabase functions serve # serve Edge Functions locally
```

- **Dependency Audit**: Scans for known vulnerabilities in npm packages
- **SARIF Upload**: Reports security findings to GitHub Security tab
3. Environment

### Deployment
Create a `.env.local` in `frontend/` (do not commit):

- **Frontend**: Automatically deployed by Vercel on push to `main`
- **Supabase Functions**: Deployed manually via Supabase CLI
```env
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=public-anon-key
```

## Development
## Scripts and common commands

### Frontend
From `frontend/`:

```bash
cd frontend
npm install
npm run dev
npm run dev # start dev server
npm run build # build production bundle
npm run preview # preview production build locally
npm run lint # run ESLint
npm run test # run tests (project tests if configured)
```

### Supabase Functions
Supabase / functions (examples):

```bash
# Requires Supabase CLI
supabase functions serve
deno check supabase/functions/*/index.ts # type check functions
deno fmt supabase/functions/*/index.ts # format functions
```

## Available Scripts
## Architecture notes

### Frontend
- Frontend organizes UI primitives under `src/components/ui` to keep shared building blocks.
- Services that talk to Supabase are in `src/services/` (e.g., `resourceService.ts`, `jobService.ts`).
- Hooks such as `use-auth` and `use-reliable-realtime` encapsulate auth state and realtime behaviors.

- `npm run dev` - Start development server
- `npm run build` - Build for production
- `npm run lint` - Run ESLint
- `npm run preview` - Preview production build
## CI / Deployment

### Supabase
- Frontend is designed to deploy to Vercel (see `frontend/vercel.json`).
- GitHub Actions run type checks, linters, build verification, and security scans for dependencies.
- Supabase functions are typically deployed using the Supabase CLI/CI; check the `.github/workflows` directory for CI workflow examples.

- `deno check index.ts` - Type check functions
- `deno fmt index.ts` - Format code
## Tests and quality gates

## Environment Variables
- Type checking: `tsc --noEmit` (frontend)
- Linting: ESLint configured in `frontend/eslint.config.js`
- Formatting: Prettier / Deno fmt for Supabase functions

Create `.env.local` in the frontend directory:
## Useful paths

```
VITE_SUPABASE_URL=your_supabase_url
VITE_SUPABASE_ANON_KEY=your_supabase_anon_key
```
- Frontend entry: `frontend/src/main.tsx`
- UI components: `frontend/src/components/ui`
- Supabase functions: `supabase/functions/*/index.ts`

## Troubleshooting

> [!TIP]
> If the frontend can't connect to Supabase locally, double-check `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` in `frontend/.env.local` and ensure `supabase start` (local emulators) is running when using local endpoints.

## Next steps / suggestions

- Add end-to-end tests (Cypress or Playwright) for the main flows (auth, resource CRUD).
- Add a small runbook for deploying Supabase functions with the CLI in CI.

---

Requirements coverage:

- Create a concise, useful README for the project — Done
- Use GFM and admonitions where helpful — Done
- Avoid sections like LICENSE/CONTRIBUTING/CHANGELOG — Done
- Include logo if present — Done (references `frontend/public/mindley-icon.svg`)

If you want, I can also update `frontend/README.md` to match this top-level README or generate a brief developer runbook next.
2 changes: 2 additions & 0 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,10 @@
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
<link rel="icon" type="image/svg+xml" href="/mindley-icon.svg" />
<link rel="shortcut icon" href="/favicon.ico" />
<link rel="manifest" href="/manifest.json" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-title" content="Mindley" />
<meta name="mobile-web-app-capable" content="yes" />
<link rel="canonical" href="https://mindley.app" />
</head>
<body>
Expand Down
4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
},
"dependencies": {
"@hookform/resolvers": "^5.2.1",
"@radix-ui/react-alert-dialog": "^1.1.15",
"@radix-ui/react-avatar": "^1.1.10",
"@radix-ui/react-collapsible": "^1.1.11",
"@radix-ui/react-dialog": "^1.1.14",
"@radix-ui/react-dropdown-menu": "^2.1.15",
"@radix-ui/react-label": "^2.1.7",
"@radix-ui/react-popover": "^1.1.14",
"@radix-ui/react-progress": "^1.1.7",
"@radix-ui/react-select": "^2.2.5",
"@radix-ui/react-separator": "^1.1.7",
"@radix-ui/react-slot": "^1.2.3",
Expand All @@ -27,7 +29,7 @@
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"input-otp": "^1.4.2",
"lucide-react": "^0.539.0",
"lucide-react": "^0.540.0",
"next-themes": "^0.4.6",
"react": "^19.1.1",
"react-dom": "^19.1.1",
Expand Down
Binary file added frontend/public/mindley-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 0 additions & 1 deletion frontend/public/mindley-og.png

This file was deleted.

40 changes: 0 additions & 40 deletions frontend/public/vite.svg

This file was deleted.

29 changes: 13 additions & 16 deletions frontend/src/components/add-resource-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
}: AddResourceFormProps) {
const [url, setUrl] = useState("");
const [language, setLanguage] = useState<"original" | "italian" | "english">(
"original",
"original"
);

const handleSubmit = (e: React.FormEvent) => {
Expand All @@ -43,7 +43,6 @@

// Reset form
setUrl("");
setLanguage("english");
};

const isValidUrl = (url: string) => {
Expand Down Expand Up @@ -81,7 +80,7 @@
type="url"
value={url}
onChange={(e) => setUrl(e.target.value)}
placeholder="https://youtube.com/watch?v=... or https://example.com/article"
placeholder="Resource Link"
className="pl-10 bg-background focus:bg-background placeholder:text-card-foreground/70"
disabled={isLoading}
/>
Expand All @@ -96,7 +95,7 @@
<div className="flex gap-2 md:w-auto w-full ">
<Select
value={language}
onValueChange={(value) => setLanguage(value as any)}

Check warning on line 98 in frontend/src/components/add-resource-form.tsx

View workflow job for this annotation

GitHub Actions / Frontend CI

Unexpected any. Specify a different type
>
<SelectTrigger className="w-32 bg-background focus:bg-background">
<SelectValue />
Expand All @@ -113,19 +112,17 @@
disabled={!canSubmit}
className="whitespace-nowrap"
>
{isLoading
? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-current mr-2" />
Processing...
</>
)
: (
<>
<Plus className="h-4 w-4 mr-2" />
Add Resource
</>
)}
{isLoading ? (
<>
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-current mr-2" />
Processing...
</>
) : (
<>
<Plus className="h-4 w-4 mr-2" />
Add Resource
</>
)}
</Button>
</div>
</form>
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/compact-resource-filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
)}
>
{/* Results header with controls */}
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-4">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 ">
<div>
<h2 className="text-2xl font-bold tracking-tight">Your Resources</h2>
<p className="text-muted-foreground">
Expand Down Expand Up @@ -85,7 +85,7 @@
{/* Content Type */}
<Select
value={filters.contentType}
onValueChange={(value: any) =>

Check warning on line 88 in frontend/src/components/compact-resource-filters.tsx

View workflow job for this annotation

GitHub Actions / Frontend CI

Unexpected any. Specify a different type
onFiltersChange({ ...filters, contentType: value })
}
>
Expand All @@ -102,7 +102,7 @@
{/* Sort */}
<Select
value={`${filters.sortBy}-${filters.sortOrder}`}
onValueChange={(value: any) => {

Check warning on line 105 in frontend/src/components/compact-resource-filters.tsx

View workflow job for this annotation

GitHub Actions / Frontend CI

Unexpected any. Specify a different type
const [sortBy, sortOrder] = value.split("-");
onFiltersChange({ ...filters, sortBy, sortOrder });
}}
Expand Down
30 changes: 30 additions & 0 deletions frontend/src/components/icons/google.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export function GoogleIcon({ className }: { className?: string }) {
return (
<svg
className={className}
viewBox="0 0 24 24"
role="img"
aria-hidden={false}
xmlns="http://www.w3.org/2000/svg"
>
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
);
}

export default GoogleIcon;
17 changes: 17 additions & 0 deletions frontend/src/components/icons/youtube.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export function YouTubeIcon({ className }: { className?: string }) {
return (
<svg
className={className}
viewBox="0 0 24 24"
role="img"
aria-hidden={false}
xmlns="http://www.w3.org/2000/svg"
>
{/* Official-ish YouTube play button: rounded red rect with white triangle */}
<rect x="1" y="4" width="22" height="16" rx="4" fill="#FF0000" />
<path d="M10 8v8l6-4-6-4z" fill="#fff" />
</svg>
);
}

export default YouTubeIcon;
Loading
Loading