snowshare
Copilot instructions108 starsChanged 8 months agoCC0-1.0View on GitHub
SnowShare: Secure file/link/paste sharing platform with user auth, quotas, and expiration. Models (prisma/schema.prisma): All shares (File/Link/Paste) follow this pattern in src/app/api/shares/(shareType)/route.ts: Anonymous limits (src/lib/quota.ts):
- Reads credentials
Where files are headingNew Copilot instructions files have more rules about branches and pull requests, and fewer about code style.
Of the Copilot instructions files we read, the 2,349 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repositoryOne other file it gives its agents.
- CLAUDE.mdCLAUDE.md
The file
Show its rules and text
We split this copilot-instructions.md into the rules it gives an agent
17 rules. About 1 is common, 4 are distinctive, and 12 are very specific to this project.
≈1
Common · estimate
Many files like this have a rule of this kind.
≈4
Distinctive · estimate
This author's own choices. Worth a look.
12
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 54
All shares (File/Link/Paste) follow this pattern in src/app/api/shares/(shareType)/route.ts:
- Very specific: line 59
Hash password: If provided, use bcryptjs cost 12
- Very specific: line 61
Store: Create Share record (files stored in uploads/ with filename: {uuid}_{originalName})
- Distinctive: line 120
Always return JSON with consistent structure (use english for messages):
- Very specific: line 128
Paths: Always use @/ alias, never relative imports like ../../../
- Very specific: line 133
Use useTranslation() from react-i18next for all UI text
- Very specific: line 139
Add keys to ALL 6 locale files in src/i18n/locales/ when adding UI text
- Distinctive: line 157
All API routes should follow this pattern:
- Very specific: line 224
Start dev server: npm run dev
- Very specific: line 247
Check DATABASE_URL in .env
- Distinctive: line 248
Ensure PostgreSQL is running
- Very specific: line 249
Verify database exists: psql -l
- Very specific: line 273
Ensure uploads/ directory exists and is writable
- Distinctive: line 274
Check disk space and quota limits
- Common: line 290
Error handling: Always validate input before DB queries.
- Very specific: line 291
Performance: Use next/image for Image optimization.
- Very specific: line 293
Coding: Use Best Practices for TypeScript, React and next.js.
≈ “Common” is an estimate: at least 1 in 5 of the 3,779 Copilot instructions files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
<!-- Copilot / AI agent instructions for the SnowShare repository -->Quick orientation
SnowShare: Secure file/link/paste sharing platform with user auth, quotas, and expiration.
- Stack: Next.js 15 (App Router) + React 19 + TypeScript + Prisma + NextAuth.js + TailwindCSS 4, PostgreSQL
- Key paths:
src/app/(routes),src/components/(UI),src/lib/(utilities),src/i18n/(i18n) - Database: PostgreSQL via Prisma; schema at
prisma/schema.prisma, client atsrc/generated/prisma/ - i18n: Client-side i18next, 6 locales (fr/en/es/de/nl/pl), auto-detected + localStorage cache
Architecture & data flow
Routes (App Router):
(shares)/f|l|p/[slug]/page.tsx → Display share by slug (File/Link/Paste)
api/shares/(fileShare|linkShare|pasteShare)/route.ts → Create shares
api/auth/[...nextauth]/route.ts → NextAuth handler
api/setup/check, /admin, /profile, /quota/... → Config & user APIs
Core services:
src/lib/auth.ts → NextAuth: CredentialsProvider + JWT (token: {id, name})
src/lib/quota.ts → Enforce upload limits by IP/user
src/lib/prisma.ts → Singleton PrismaClient
src/middleware.ts → Security headers, setup redirect, route protectionModels (prisma/schema.prisma):
User(auth): email, password (bcrypt), isAdmin, sharesShare(core): type (FILE|PASTE|URL), slug, password, expiresAt, ipSource, ownerSettings: allowSignup, quotas (fileMax, totalMax)Account,Session,VerificationToken(NextAuth)
Authentication system (critical)
- Provider: CredentialsProvider (
src/lib/auth.ts) — email/password, bcrypt hashing (cost 12) - Strategy: JWT with callbacks sync
token.id+token.nameto session - Session access:
const session = await getServerSession(authOptions)in API routes - First user auto-admin: Registered via
/api/auth/register→isAdmin: true(no admins yet) - Signup toggle: Database
Settings.allowSignup(checked via/api/setup/check). RespectsNEXT_PUBLIC_ALLOW_SIGNUPenv - Protected routes: Middleware in
src/middleware.tsredirects unauthenticated users from/profile,/admin, protected APIs - Session module: Extend with
interface User { id, name? }andinterface JWT { id, name? }insrc/lib/auth.ts
// API route: check auth & get user ID
const session = await getServerSession(authOptions);
if (!session?.user?.id) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
// Now use session.user.idShare creation flow
All shares (File/Link/Paste) follow this pattern in src/app/api/shares/(shareType)/route.ts:
- Validate: Input schema, URL format (links), file size (files)
- Check quota:
checkUploadQuota(request, fileSize)→ tracks by IP + user - Auth check: Extract session; set
ownerIdif authenticated (null for anon) - Hash password: If provided, use
bcryptjscost 12 - Generate slug: Unique, alphanumeric/hyphen/underscore, 3-30 chars (or use provided)
- Store: Create
Sharerecord (files stored inuploads/with filename:{uuid}_{originalName}) - Return:
{ share: { slug, expiresAt, ... } }or{ error: "..." }
Anonymous limits (src/lib/quota.ts):
- Max 7-day expiration (must set expiration)
- Lower file/total quotas vs authenticated users
- IP-based tracking (no session ID)
Developer commands
Development
npm run dev # Next.js dev with Turbopack (default: port 3000)
npm run build # Production build (output: .next/)
npm run start # Production server (after build)
npm run lint # Run ESLint
npm run lint:fix # ESLint auto-fixTesting
npm run test # Jest unit tests (jsdom environment)
npm run test:watch # Watch mode
npm run test:coverage # Coverage reportDatabase
npx prisma migrate dev --name <name> # Create + apply migration
npx prisma migrate deploy # Apply migrations (production)
npx prisma generate # Regenerate client → src/generated/prisma/
npx prisma db seed # Run prisma/seed.ts (if exists)
npx prisma studio # Open Prisma Studio GUIMaintenance
npm run cleanup:expired # Remove expired shares (tsx script)Docker: docker compose up -d --build — runs Next.js + PostgreSQL, executes prisma migrate deploy on startup. App at http://localhost:3000, DB at port 5432. Volumes: db-data/ (persistent), uploads/ (files).
Environment vars (.env or docker-compose.yml):
DATABASE_URL: PostgreSQL connection stringNEXTAUTH_URL: Base URL (http://localhost:3000)NEXTAUTH_SECRET: Random JWT secret (useopenssl rand -base64 32)ALLOW_SIGNUP: Boolean (controlsSettings.allowSignup, exported asNEXT_PUBLIC_ALLOW_SIGNUP)PORT: Dev server port (default 3000)
Project conventions
API responses
Always return JSON with consistent structure (use english for messages):
- Success:
{ share: {...} },{ user: {...} },{ message: "..." },{ data: [...] } - Error:
{ error: "message" }with appropriate HTTP status (400, 401, 403, 409, 429, etc.)
Imports
- Prisma:
import { prisma } from "@/lib/prisma"andimport { ... } from "@/generated/prisma" - Paths: Always use
@/alias, never relative imports like../../../
Client components
- Mark with
"use client"at top of file - Use
useTranslation()from react-i18next for all UI text - Access auth with
useSession()from next-auth/react, oruseAuth()hook - State management: simple
useState(no Redux/Zustand)
Translations
- Add keys to ALL 6 locale files in
src/i18n/locales/when adding UI text - Fallback language is english (
en) - Pattern:
t("section.key", "English default")
Styling
- TailwindCSS 4 and material ui
- Component library: React Material UI
- Responsive: Mobile-first approach
File uploads
- Store in
uploads/directory with pattern:{uuid}_{originalName}(uuid via crypto) - Track file path in
Share.filePath(relative to project root) - Clean up files when shares expire (via cleanup script)
Error handling patterns
All API routes should follow this pattern:
// Validation errors → 400
if (!isValid) {
return NextResponse.json({ error: "Invalid input" }, { status: 400 });
}
// Unauthorized → 401
if (!session) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// Forbidden → 403
if (!hasPermission) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}
// Quota exceeded → 429
if (quotaExceeded) {
return NextResponse.json({ error: "Quota exceeded" }, { status: 429 });
}
// Success → 200
return NextResponse.json({ data: result });Key files for common tasks
| Task | Files |
| Add API endpoint | src/app/api/<name>/route.ts — export GET/POST/etc |
| Modify auth | src/lib/auth.ts (callbacks), src/app/api/auth/register/route.ts |
| Add share type | src/app/api/shares/, new (typeShare)/ folder + display at src/app/(shares)/ |
| Add UI component | src/components/ — check Navigation.tsx for client/server patterns |
| Add translation | All files in src/i18n/locales/*.json (fr, en, es, de, nl, pl) |
| Change quotas | prisma/schema.prisma Settings model, src/lib/quota.ts enforcement |
| Database operations | All at src/app/api/ routes; client at src/generated/prisma |
CI/CD workflow
The repository uses GitHub Actions for CI/CD:
- build-self-hosted.yml: Runs on push/PR to main/dev branches
- Checkout code
- Setup Node.js 20
- Install dependencies (
npm ci) - Run linter (
npm run lint) - Build Docker image
- Triggered on:
pushto main/dev,pull_requestopened/synchronize/reopened - Tests are run via Jest framework (see Testing section)
Environment setup
Initial Setup
- Clone repository:
git clone https://github.com/TuroYT/snowshare.git - Install dependencies:
npm install - Copy
.env.exampleto.envand configure:DATABASE_URL="postgresql://user:pass@localhost:5432/snowshare" NEXTAUTH_URL="http://localhost:3000" NEXTAUTH_SECRET="$(openssl rand -base64 32)" ALLOW_SIGNUP=true - Initialize database:
npx prisma migrate dev - Generate Prisma client:
npx prisma generate - Start dev server:
npm run dev
Docker Setup (Alternative)
docker compose up -d --build
# App: http://localhost:3000
# DB: PostgreSQL on port 5432
# Data persists in db-data/ and uploads/Troubleshooting
Common Issues
Prisma Client not generated
npx prisma generateDatabase connection errors
- Check
DATABASE_URLin.env - Ensure PostgreSQL is running
- Verify database exists:
psql -l
Port 3000 already in use
# Change PORT in .env or use:
PORT=3001 npm run devESLint errors
npm run lint:fix # Auto-fix issuesTest failures after DB schema change
npx prisma generate # Regenerate client
npm test # Re-run testsFile upload issues
- Ensure
uploads/directory exists and is writable - Check disk space and quota limits
Related documentation
- CONTRIBUTING.md - Contribution guidelines and workflow
- README.md - Project overview and getting started
- SECURITY.md - Security policy and reporting
- prisma/schema.prisma - Database schema
AI agent guidelines
- ⚠️ Migration caution: Prisma migrations are irreversible in production. Test locally first.
- ⚠️ Auth changes: JWT callbacks in
src/lib/auth.tsmust stay in sync — bothjwtandsessioncallbacks - Validate slugs: Regex pattern
/^[a-zA-Z0-9_-]{3,30}$/for share slugs - IP tracking: File uploads track IP via
getClientIp()insrc/lib/quota.tsfor quota enforcement - Setup flow: First visit triggers setup check in middleware → redirects to
/setupif no users exist - Error handling: Always validate input before DB queries; return 400 (bad), 401 (auth), 403 (forbidden), 429 (quota)
- Performance: Use
next/imagefor Image optimization; leverage Next.js caching and ISR where applicable - Security: Sanitize all user inputs; hash passwords with bcrypt (cost 12); use HTTPS in production
- Coding: Use Best Practices for TypeScript, React and next.js; keep functions small and focused; add comments for complex logic
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

