Compare commits
125 Commits
v2.0.0-bet
...
v3.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
|
828fbd4cfd | ||
|
ea68e771a8 | ||
|
229f9a3ca0 | ||
|
dd10c17a3a | ||
|
ab071916b8 | ||
|
1ab0504288 | ||
|
652f1f47d2 | ||
|
cd9598a6d3 | ||
|
017a1debd3 | ||
|
b917dbc05f | ||
|
4fdee6b98b | ||
|
a669a6c048 | ||
|
264521f1c4 | ||
|
b1cc9dbb21 | ||
|
719b7f0036 | ||
|
68c565f265 | ||
|
22c5a44af8 | ||
|
4e841b272c | ||
|
6af10c6f33 | ||
|
978a1e5755 | ||
|
c265b8e08d | ||
|
d0173a0bf9 | ||
|
0d346b75cc | ||
|
0a65917cbf | ||
|
f651f50180 | ||
|
1125665bb1 | ||
|
b65aac3044 | ||
|
a865aabed0 | ||
|
561e8faf33 | ||
|
6445b0ce3e | ||
|
90cd3333cb | ||
|
2ca0db70c3 | ||
|
28697fa270 | ||
|
d739c1b213 | ||
|
25a0c39135 | ||
|
185fa4c191 | ||
|
9dfb034c2e | ||
|
936a2b71c7 | ||
|
cd14c28be1 | ||
|
3c084a6686 | ||
|
6a1381684b | ||
|
dc20770fe6 | ||
|
6e526f7f88 | ||
|
858852c8cd | ||
|
363dedbb2c | ||
|
cd215c79b8 | ||
|
98586efbcd | ||
|
c724e644c7 | ||
|
555ff18a87 | ||
|
5100e1591b | ||
|
6de29bbf07 | ||
|
39c47be940 | ||
|
76d96816bc | ||
|
b3e7658a76 | ||
|
61a579aeb3 | ||
|
cc9c375774 | ||
|
016006ba3d | ||
|
cbc567c6a8 | ||
|
25b4d886f7 | ||
|
98953e042b | ||
|
9e06a67593 | ||
|
9682f96905 | ||
|
d2c69c3b36 | ||
|
9afe8292fa | ||
|
e15f50a8a8 | ||
|
8affdc8f95 | ||
|
281eff0f14 | ||
|
b28f1f97c4 | ||
|
c5660b3c6b | ||
|
e64f718998 | ||
|
f00a9dadd0 | ||
|
c262c164d2 | ||
|
1d882252e3 | ||
|
2ea7343e0c | ||
|
54bd987b9a | ||
|
b900953674 | ||
|
d07ebfd01f | ||
|
5b0b01eecd | ||
|
cb87505afd | ||
|
b447204908 | ||
|
4049878cfe | ||
|
13ae0d3b8c | ||
|
2990e6fefb | ||
|
65c9b755ca | ||
|
893a4097b6 | ||
|
d3c26b550b | ||
|
348bdb0282 | ||
|
8f30883404 | ||
|
458c6b40bb | ||
|
fea4faa7ce | ||
|
6a08874267 | ||
|
b549aef45f | ||
|
1fb06067cd | ||
|
998b690659 | ||
|
459783b152 | ||
|
bc752b3b74 | ||
|
f067e160ba | ||
|
5f4f8acbca | ||
|
1a34236208 | ||
|
14477ff676 | ||
|
ff6e171e91 | ||
|
d69453e4ae | ||
|
158858e426 | ||
|
b90c77966d | ||
|
9dff734f9f | ||
|
d3b7fe04ed | ||
|
122781ca3d | ||
|
32727bf99b | ||
|
9baf3588c0 | ||
|
3677b6e494 | ||
|
7a77c0a1c1 | ||
|
6c4dbb167e | ||
|
d74ff76227 | ||
|
713ad709a6 | ||
|
c39d41b76c | ||
|
602780e8dd | ||
|
2276ed5bd6 | ||
|
4b57a03311 | ||
|
fff4675aa3 | ||
|
8290ccaaa9 | ||
|
c780ea2f2a | ||
|
615d203002 | ||
|
9984a21b76 | ||
|
431086a614 | ||
|
d40ef51695 |
81
.dockerignore
Normal file
@@ -0,0 +1,81 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
|
||||
# Documentation
|
||||
README.md
|
||||
CONTRIBUTING.md
|
||||
*.md
|
||||
|
||||
# Node modules
|
||||
node_modules
|
||||
*/node_modules
|
||||
**/node_modules
|
||||
|
||||
# Build outputs
|
||||
.next
|
||||
dist
|
||||
build
|
||||
|
||||
# Development files
|
||||
.env*
|
||||
.vscode
|
||||
.idea
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
logs
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
*.pid.lock
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Dependency directories
|
||||
jspm_packages/
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# Output of 'npm pack'
|
||||
*.tgz
|
||||
|
||||
# Yarn Integrity file
|
||||
.yarn-integrity
|
||||
|
||||
# dotenv environment variables file
|
||||
.env
|
||||
|
||||
# Docker files
|
||||
Dockerfile*
|
||||
docker-compose*
|
||||
|
||||
# Storage directories (created at runtime)
|
||||
uploads/
|
||||
temp-chunks/
|
||||
apps/server/uploads/
|
||||
apps/server/temp-chunks/
|
||||
|
||||
# Static files
|
||||
apps/server/prisma/*.db
|
||||
apps/server/.env
|
||||
apps/web/.env
|
||||
|
||||
# OS generated files
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
._*
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
ehthumbs.db
|
||||
Thumbs.db
|
56
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
## **🎯 Please make sure you are opening this Pull Request against the `next` branch!**
|
||||
|
||||
## 📝 Description
|
||||
|
||||
Please provide a clear and concise description of the changes introduced by this pull request.
|
||||
|
||||
## 🔗 Related Issue(s)
|
||||
|
||||
If this PR fixes or relates to an issue, please link it here (e.g., `Closes #123`).
|
||||
|
||||
## 💡 Motivation and Context
|
||||
|
||||
Why is this change required? What problem does it solve?
|
||||
|
||||
## 🤖 Use of Artificial Intelligence (AI)
|
||||
|
||||
The use of AI tools is absolutely welcome and not an issue. For transparency and continuous improvement, please answer the following:
|
||||
|
||||
- Did you use any AI tools (such as GitHub Copilot, ChatGPT, etc.) to help develop this PR?
|
||||
- [ ] No, this PR was developed without the assistance of AI tools.
|
||||
- [ ] Yes, AI tools assisted in the development of this PR (please specify which ones and how they were used):
|
||||
- Tool(s) used:
|
||||
- Brief description of how AI contributed:
|
||||
- Was this PR generated entirely by an AI tool (i.e., with minimal human intervention)?
|
||||
- [ ] No
|
||||
- [ ] Yes (please provide details):
|
||||
|
||||
## 🧪 How Has This Been Tested?
|
||||
|
||||
Please describe the tests that you ran to verify your changes. Include details about your test environment, and the test cases you ran.
|
||||
|
||||
## 📸 Screenshots (if appropriate)
|
||||
|
||||
Add any relevant screenshots to help explain your changes.
|
||||
|
||||
## 🔄 Types of Changes
|
||||
|
||||
Check the relevant option(s) below:
|
||||
|
||||
- [ ] 🐛 Bug fix (non-breaking change which fixes an issue)
|
||||
- [ ] ✨ New feature (non-breaking change which adds functionality)
|
||||
- [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change)
|
||||
- [ ] 📚 Documentation update
|
||||
|
||||
## ✅ Checklist
|
||||
|
||||
- [ ] My code follows the code style of this project
|
||||
- [ ] I have performed a self-review of my code
|
||||
- [ ] I have commented my code, particularly in hard-to-understand areas
|
||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
||||
- [ ] I have added necessary documentation (if appropriate)
|
||||
- [ ] I have rebased and/or merged on top of the latest `next` branch
|
||||
|
||||
---
|
||||
|
||||
🙏 Thank you for your contribution!
|
3
.gitignore
vendored
@@ -29,4 +29,5 @@ apps/server/.env
|
||||
apps/server/dist/*
|
||||
|
||||
#DEFAULT
|
||||
.env
|
||||
.env
|
||||
data/
|
165
Dockerfile
Normal file
@@ -0,0 +1,165 @@
|
||||
FROM node:20-alpine AS base
|
||||
|
||||
# Install system dependencies
|
||||
RUN apk add --no-cache \
|
||||
gcompat \
|
||||
supervisor \
|
||||
curl \
|
||||
su-exec
|
||||
|
||||
# Enable pnpm
|
||||
RUN corepack enable pnpm
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app
|
||||
|
||||
# === SERVER BUILD STAGE ===
|
||||
FROM base AS server-deps
|
||||
WORKDIR /app/server
|
||||
|
||||
# Copy server package files
|
||||
COPY apps/server/package*.json ./
|
||||
COPY apps/server/pnpm-lock.yaml ./
|
||||
|
||||
# Install server dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS server-builder
|
||||
WORKDIR /app/server
|
||||
|
||||
# Copy server dependencies
|
||||
COPY --from=server-deps /app/server/node_modules ./node_modules
|
||||
|
||||
# Copy server source code
|
||||
COPY apps/server/ ./
|
||||
|
||||
# Generate Prisma client
|
||||
RUN npx prisma generate
|
||||
|
||||
# Build server
|
||||
RUN pnpm build
|
||||
|
||||
# === WEB BUILD STAGE ===
|
||||
FROM base AS web-deps
|
||||
WORKDIR /app/web
|
||||
|
||||
# Copy web package files
|
||||
COPY apps/web/package.json apps/web/pnpm-lock.yaml ./
|
||||
|
||||
# Install web dependencies
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
FROM base AS web-builder
|
||||
WORKDIR /app/web
|
||||
|
||||
# Copy web dependencies
|
||||
COPY --from=web-deps /app/web/node_modules ./node_modules
|
||||
|
||||
# Copy web source code
|
||||
COPY apps/web/ ./
|
||||
|
||||
# Set environment variables for build
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV NODE_ENV=production
|
||||
|
||||
# Build web application
|
||||
RUN pnpm run build
|
||||
|
||||
# === PRODUCTION STAGE ===
|
||||
FROM base AS runner
|
||||
|
||||
# Set production environment
|
||||
ENV NODE_ENV=production
|
||||
ENV NEXT_TELEMETRY_DISABLED=1
|
||||
ENV API_BASE_URL=http://127.0.0.1:3333
|
||||
|
||||
# Define build arguments for user/group configuration (defaults to current values)
|
||||
ARG PALMR_UID=1001
|
||||
ARG PALMR_GID=1001
|
||||
|
||||
# Create application user with configurable UID/GID
|
||||
RUN addgroup --system --gid ${PALMR_GID} nodejs
|
||||
RUN adduser --system --uid ${PALMR_UID} --ingroup nodejs palmr
|
||||
|
||||
# Create application directories
|
||||
RUN mkdir -p /app/palmr-app /app/web /home/palmr/.npm /home/palmr/.cache
|
||||
RUN chown -R palmr:nodejs /app /home/palmr
|
||||
|
||||
# === Copy Server Files to /app/palmr-app (separate from /app/server for bind mounts) ===
|
||||
WORKDIR /app/palmr-app
|
||||
|
||||
# Copy server production files
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/dist ./dist
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/node_modules ./node_modules
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/prisma ./prisma
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/package.json ./
|
||||
|
||||
# Copy password reset script and make it executable
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/reset-password.sh ./
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/src/scripts/ ./src/scripts/
|
||||
RUN chmod +x ./reset-password.sh
|
||||
|
||||
# Copy seed file to the shared location for bind mounts
|
||||
RUN mkdir -p /app/server/prisma
|
||||
COPY --from=server-builder --chown=palmr:nodejs /app/server/prisma/seed.js /app/server/prisma/seed.js
|
||||
|
||||
# === Copy Web Files ===
|
||||
WORKDIR /app/web
|
||||
|
||||
# Copy web production files
|
||||
COPY --from=web-builder --chown=palmr:nodejs /app/web/public ./public
|
||||
COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/standalone ./
|
||||
COPY --from=web-builder --chown=palmr:nodejs /app/web/.next/static ./.next/static
|
||||
|
||||
# === Setup Supervisor ===
|
||||
WORKDIR /app
|
||||
|
||||
# Create supervisor configuration
|
||||
RUN mkdir -p /etc/supervisor/conf.d
|
||||
|
||||
# Copy server start script
|
||||
COPY infra/server-start.sh /app/server-start.sh
|
||||
RUN chmod +x /app/server-start.sh
|
||||
RUN chown palmr:nodejs /app/server-start.sh
|
||||
|
||||
# Copy supervisor configuration
|
||||
COPY infra/supervisord.conf /etc/supervisor/conf.d/supervisord.conf
|
||||
|
||||
# Create main startup script
|
||||
COPY <<EOF /app/start.sh
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "Starting Palmr Application..."
|
||||
echo "Storage Mode: \${ENABLE_S3:-false}"
|
||||
echo "Secure Site: \${SECURE_SITE:-false}"
|
||||
echo "Database: SQLite"
|
||||
|
||||
# Set global environment variables
|
||||
export DATABASE_URL="file:/app/server/prisma/palmr.db"
|
||||
export UPLOAD_PATH="/app/server/uploads"
|
||||
export TEMP_CHUNKS_PATH="/app/server/temp-chunks"
|
||||
|
||||
# Ensure /app/server directory exists for bind mounts
|
||||
mkdir -p /app/server/uploads /app/server/temp-chunks /app/server/uploads/logo /app/server/prisma
|
||||
|
||||
echo "Data directories ready for first run..."
|
||||
|
||||
# Start supervisor
|
||||
exec /usr/bin/supervisord -c /etc/supervisor/conf.d/supervisord.conf
|
||||
EOF
|
||||
|
||||
RUN chmod +x /app/start.sh
|
||||
|
||||
# Create volume mount points for bind mounts
|
||||
VOLUME ["/app/server"]
|
||||
|
||||
# Expose ports
|
||||
EXPOSE 3333 5487
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f http://localhost:5487 || exit 1
|
||||
|
||||
# Start application
|
||||
CMD ["/app/start.sh"]
|
37
LICENSE
@@ -1,22 +1,37 @@
|
||||
BSD 2-Clause License
|
||||
Kyantech-Permissive License (Based on BSD 2-Clause)
|
||||
|
||||
Copyright (c) 2025, Daniel Luiz Alves (danielalves96)
|
||||
Copyright (c) 2025, Daniel Luiz Alves (danielalves96) - Kyantech Solutions
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
modification, are permitted for any purpose — private, commercial,
|
||||
educational, governmental — **fully free and unrestricted**, provided
|
||||
that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions, and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions, and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. **If this software (or derivative works) is used in any public-facing
|
||||
interface** — such as websites, apps, dashboards, admin panels, or
|
||||
similar — a **simple credit** must appear in the footer or similar
|
||||
location. The credit text should read:
|
||||
|
||||
> “Powered by Kyantech Solutions · https://kyantech.com.br”
|
||||
|
||||
This credit must be reasonably visible but **must not interfere** with
|
||||
your UI, branding, or user experience. You may style it to match your
|
||||
own design and choose its size, placement, or color.
|
||||
|
||||
---
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
|
47
Makefile
Normal file
@@ -0,0 +1,47 @@
|
||||
.PHONY: help build start clean logs stop restart
|
||||
|
||||
# Default target
|
||||
help:
|
||||
@echo "🚀 Palmr - Available Commands:"
|
||||
@echo ""
|
||||
@echo " make build - Build Docker image with multi-platform support"
|
||||
@echo " make start - Start the application using docker-compose"
|
||||
@echo " make stop - Stop all running containers"
|
||||
@echo " make logs - Show application logs"
|
||||
@echo " make clean - Clean up containers and images"
|
||||
@echo " make shell - Access the application container shell"
|
||||
@echo ""
|
||||
@echo "📁 Scripts location: ./infra/"
|
||||
|
||||
# Build Docker image using the build script
|
||||
build:
|
||||
@echo "🏗️ Building Palmr Docker image..."
|
||||
@chmod +x ./infra/build-docker.sh
|
||||
@./infra/build-docker.sh
|
||||
|
||||
# Start the application
|
||||
start:
|
||||
@echo "🚀 Starting Palmr application..."
|
||||
@docker-compose up -d
|
||||
|
||||
# Stop the application
|
||||
stop:
|
||||
@echo "🛑 Stopping Palmr application..."
|
||||
@docker-compose down
|
||||
|
||||
# Show logs
|
||||
logs:
|
||||
@echo "📋 Showing Palmr logs..."
|
||||
@docker-compose logs -f
|
||||
|
||||
# Clean up containers and images
|
||||
clean:
|
||||
@echo "🧹 Cleaning up Docker containers and images..."
|
||||
@docker-compose down -v
|
||||
@docker system prune -f
|
||||
@echo "✅ Cleanup completed!"
|
||||
|
||||
# Access container shell
|
||||
shell:
|
||||
@echo "🐚 Accessing Palmr container shell..."
|
||||
@docker-compose exec palmr /bin/sh
|
86
README.md
@@ -1,7 +1,7 @@
|
||||
# 🌴 Palmr. - Open-Source File Transfer
|
||||
|
||||
<p align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1745548261/Palmr./banner_roxtph.png" alt="Palmr Logo" style="width: 100%;">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749825361/Group_47_1_bcx8gw.png" alt="Palmr Banner" style="width: 100%;"/>
|
||||
</p>
|
||||
|
||||
**Palmr.** is a **flexible** and **open-source** alternative to file transfer services like **WeTransfer**, **SendGB**, **Send Anywhere**, and **Files.fm**.
|
||||
@@ -14,6 +14,8 @@
|
||||
- **Self-hosted** – Deploy on your own server or VPS.
|
||||
- **Full control** – No third-party dependencies, ensuring privacy and security.
|
||||
- **No artificial limits** – Share files without hidden restrictions or fees.
|
||||
- **Simple deployment** – SQLite database and filesystem storage for easy setup.
|
||||
- **Scalable storage** – Optional S3-compatible object storage for enterprise needs.
|
||||
|
||||
## 🚀 Technologies Used
|
||||
|
||||
@@ -26,8 +28,8 @@
|
||||
|
||||
### **Backend & API**
|
||||
- **Fastify (Node.js)** – High-performance API framework with built-in schema validation.
|
||||
- **PostgreSQL** – Reliable, secure, and scalable database solution.
|
||||
- **MinIO (Object Storage)** – AWS S3-compatible storage for high availability.
|
||||
- **SQLite** – Lightweight, reliable database with zero-configuration setup.
|
||||
- **Filesystem Storage** – Direct file storage with optional S3-compatible object storage.
|
||||
|
||||
### **Frontend**
|
||||
- **NextJS 15 + TypeScript + Shadcn/ui** – Modern and fast web interface.
|
||||
@@ -36,9 +38,80 @@
|
||||
## 🛠️ How It Works
|
||||
|
||||
1. **Web Interface** → Built with Next, React and TypeScript for a seamless user experience.
|
||||
2. **Backend API** → Fastify handles requests and interacts with storage.
|
||||
3. **Database** → PostgreSQL stores metadata and transactional data.
|
||||
4. **Storage** → MinIO ensures reliable file storage and retrieval.
|
||||
2. **Backend API** → Fastify handles requests and manages file operations.
|
||||
3. **Database** → SQLite stores metadata and transactional data with zero configuration.
|
||||
4. **Storage** → Filesystem storage ensures reliable file storage with optional S3-compatible object storage for scalability.
|
||||
|
||||
## 📸 Screenshots
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824929/Login_veq6e7.png" alt="Login Page" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Login Page</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824929/Home_lzvfzu.png" alt="Home Page" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Home Page</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/Dashboard_uycmxb.png" alt="Dashboard" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Dashboard</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824929/Profile_wvnlzw.png" alt="Profile Page" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Profile Page</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/Files_List_ztwr1e.png" alt="Files List View" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Files List View</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/Files_Cards_pwsh5e.png" alt="Files Card View" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Files Card View</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824927/Shares_cgplgw.png" alt="Shares Management" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Shares Management</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/Reive_Files_uhkeyc.png" alt="Receive Files" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Receive Files</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824927/Default_Reverse_xedmhw.png" alt="Reverse Share" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Reverse Share</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/Settings_oampxr.png" alt="Settings Panel" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Settings Panel</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/User_Management_xjbfhn.png" alt="User Management" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>User Management</strong>
|
||||
</td>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/Forgot_Password_jcz9ad.png" alt="Forgot Password" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Forgot Password</strong>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<img src="https://res.cloudinary.com/technical-intelligence/image/upload/v1749824928/WeTransfer_Reverse_u0g7eb.png" alt="Forgot Password" style="width: 100%; border-radius: 8px;" />
|
||||
<br /><strong>Reverse Share (WeTransfer Style)</strong>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
## 👨💻 Core Maintainers
|
||||
@@ -66,3 +139,4 @@
|
||||
## 🛠️ Contributing
|
||||
|
||||
For contribution guidelines, please refer to the [CONTRIBUTING.md](CONTRIBUTING.md) file.
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"title": "v1.1.7-beta",
|
||||
"description": "(Deprecated)",
|
||||
"root": true,
|
||||
"icon": "Building2",
|
||||
"icon": "Trash2",
|
||||
"pages": [
|
||||
"---Introduction---",
|
||||
"index",
|
||||
@@ -25,4 +25,4 @@
|
||||
"gh-star",
|
||||
"gh-sponsor"
|
||||
]
|
||||
}
|
||||
}
|
@@ -29,15 +29,16 @@ Below is the complete content of our `docker-compose.yaml` that can be copied di
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr-api:
|
||||
image: kyantech/palmr-api:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr-api
|
||||
palmr:
|
||||
image: kyantech/palmr:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr
|
||||
depends_on:
|
||||
postgres:
|
||||
condition: "service_healthy"
|
||||
minio:
|
||||
condition: "service_healthy"
|
||||
environment:
|
||||
# Server environment variables
|
||||
- PORT=${API_INTERNAL_PORT:-3333} # Port for the backend service
|
||||
- DATABASE_URL=postgresql://postgres:${POSTGRESQL_PASSWORD:-postgresRootPassword}@postgres:5432/palmr_db?schema=public # Database URL with configurable password through POSTGRESQL_PASSWORD env var
|
||||
- MINIO_ENDPOINT=${MINIO_ENDPOINT:-minio} # This can change if your MinIO is at a different address
|
||||
@@ -50,34 +51,21 @@ services:
|
||||
- FRONTEND_URL=${APP_URL:-http://${SERVER_IP:-localhost}:${APP_EXTERNAL_PORT:-5487}} # Frontend URL - Make sure to use the correct frontend URL, depends on where the frontend is running, its prepared for localhost, but you can change it to your frontend URL if needed
|
||||
- SERVER_IP=${SERVER_IP:-localhost} # Server IP - Make sure to use the correct server IP if you running on a cloud provider or a virtual machine. This prepared for localhost, but you can change it to your server IP if needed
|
||||
- MAX_FILESIZE=${MAX_FILESIZE:-1073741824} # Max Filesize for upload - Declared in Bytes. Default is 1GiB
|
||||
ports:
|
||||
- "${API_EXTERNAL_PORT:-3333}:${API_INTERNAL_PORT:-3333}" # Backend port mapping
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "wget", "--no-verbose", "http://palmr-api:${API_INTERNAL_PORT:-3333}/health"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
|
||||
palmr-app:
|
||||
image: kyantech/palmr-app:latest # Make sure to use the correct version (latest) of the image
|
||||
container_name: palmr-web
|
||||
depends_on:
|
||||
palmr-api:
|
||||
condition: "service_healthy"
|
||||
ports:
|
||||
- "${APP_EXTERNAL_PORT:-5487}:5487" # Frontend port mapping
|
||||
environment:
|
||||
|
||||
# Web environment variables
|
||||
- NODE_ENV=production
|
||||
- NEXT_TELEMETRY_DISABLED=1
|
||||
- API_BASE_URL=http://palmr-api:${API_INTERNAL_PORT:-3333} # Here we use docker's internal network to reference the backend service (can be changed if needed)
|
||||
- API_BASE_URL=http://palmr:${API_INTERNAL_PORT:-3333} # Using Docker service name for internal communication
|
||||
ports:
|
||||
- "${API_EXTERNAL_PORT:-3333}:3333" # Server port
|
||||
- "${APP_EXTERNAL_PORT:-5487}:5487" # Web port
|
||||
restart: unless-stopped
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:5487"]
|
||||
test: ["CMD", "wget", "--no-verbose", "http://palmr:${API_INTERNAL_PORT:-3333}/health", "&&", "wget", "--no-verbose", "http://palmr:${APP_INTERNAL_PORT:-5487}"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
|
||||
minio:
|
||||
image: minio/minio:RELEASE.2025-03-12T18-04-18Z # Use only version RELEASE.2025-03-12T18-04-18Z to avoid compatibility issues with the backend
|
||||
@@ -138,7 +126,7 @@ services:
|
||||
|
||||
volumes:
|
||||
minio_data:
|
||||
postgres_data:
|
||||
postgres_data:
|
||||
|
||||
```
|
||||
|
||||
@@ -148,12 +136,11 @@ Notice that the `docker-compose.yaml` has several comments that help you configu
|
||||
|
||||
### ⚙️ Services Overview
|
||||
|
||||
Palmr. consists of five main services, each with specific responsibilities. Below, we present a detailed view of each component:
|
||||
Palmr. consists of four main services, each with specific responsibilities. Below, we present a detailed view of each component:
|
||||
|
||||
| **Service** | **Image** | **Exposed Ports** | **Main Features** |
|
||||
| --- | --- | --- | --- |
|
||||
| palmr-api (Backend) | [kyantech/palmr-api:latest](https://hub.docker.com/repository/docker/kyantech/palmr-api/tags/latest/sha256-84245d3d0012aa65c588caba56322363729c4b68c3722a08dcda912904de9d1d) | **3333** | • Main API service<br/>• Depends on services: postgres and minio<br/>• Has healthcheck to ensure availability |
|
||||
| palmr-app (Frontend) | [kyantech/palmr-app:latest](https://hub.docker.com/repository/docker/kyantech/palmr-app/tags/latest/sha256-33f568673ae8cc8529532146b6afc1acafa203387ced6c7bb3451a7ab4198a2f) | **5487** | • Web application interface<br/>• Depends on palmr-api service<br/>• Configured for production environment |
|
||||
| palmr | [kyantech/palmr:latest](https://hub.docker.com/repository/docker/kyantech/palmr/general) | **3333** (API)<br/>**5487** (Web) | • Combined backend API and frontend service<br/>• Depends on services: postgres and minio<br/>• Has healthcheck to ensure availability |
|
||||
| minio (Storage) | [minio/minio:RELEASE.2025-03-12T18-04-18Z](https://hub.docker.com/layers/minio/minio/RELEASE.2025-03-12T18-04-18Z/images/sha256-85f3e4cd1ca92a2711553ab79f222bcd8b75aa2c77a1a0b0ccf80d38e8ab2fe5) | **6421**(API)<br/>**6422**(Console) | • File storage service<br/>• Persistent volume for data |
|
||||
| minio-init (Config) | [minio/mc:RELEASE.2025-03-12T17-29-24Z](https://hub.docker.com/layers/minio/mc/RELEASE.2025-03-12T17-29-24Z/images/sha256-68d8c80f43908b02daa285e55547131870a1d36b3ffe272c26d7d8f4d52d1e5c) | N/A | • Initially configures the "files" bucket<br/>• Runs only once during initialization |
|
||||
| postgres (Database) | [bitnami/postgresql:17.2.0](https://hub.docker.com/layers/bitnami/postgresql/17.2.0/images/sha256-29c614afad4f514b12b5c0f4d006f38c98fa4b18c3582732ff93b3fe9a79d875) | **5432** | • PostgreSQL database<br/>• Persistent volume for data |
|
||||
@@ -197,13 +184,17 @@ The table below shows all environment variables that can be set
|
||||
|
||||
In a localhost environment, there's no mystery. If you don't want to change any service exposure ports, you can simply run:
|
||||
|
||||
```bash
|
||||
docker compose pull && docker compose up -d
|
||||
```
|
||||
|
||||
This will execute all necessary services and give you access to the following URLs (if you haven't changed any ports):
|
||||
|
||||
- **Frontend:** [http://localhost:5487](http://localhost:5487)
|
||||
- **Backend:** [http://localhost:3333](http://localhost:3333/)
|
||||
- **MinIO API:** [http://localhost:6421](http://localhost:6421)
|
||||
- **MinIO Console:** [http://localhost:6422](http://localhost:6422)
|
||||
- **Postgres Database:** [http://localhost:5423](http://localhost:5423/) (Connection only)
|
||||
- **Postgres Database:** [http://localhost:5432](http://localhost:5432/) (Connection only)
|
||||
|
||||
> *If you have changed any port, simply access the URL with the port you configured.*
|
||||
>
|
||||
@@ -247,7 +238,7 @@ If you haven't changed the execution ports, you'll have access on your server at
|
||||
- **Backend:** `[server_ip]:3333`
|
||||
- **MinIO API:** `[server_ip]:6421`
|
||||
- **MinIO Console:** `[server_ip]:6422`
|
||||
- **Postgres Database:** `[server_ip]:5423` (Connection only)
|
||||
- **Postgres Database:** `[server_ip]:5432` (Connection only)
|
||||
|
||||
> *If you've changed any port, simply access the URL with the port you configured.*
|
||||
>
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"title": "v2.0.0-beta",
|
||||
"description": "v2.0.0-beta Documentation",
|
||||
"description": "(Deprecated)",
|
||||
"root": true,
|
||||
"icon": "Building2",
|
||||
"icon": "Trash2",
|
||||
"pages": [
|
||||
"---Introduction---",
|
||||
"index",
|
||||
@@ -11,6 +11,7 @@
|
||||
"installation",
|
||||
"manual-installation",
|
||||
"api",
|
||||
"s3-providers",
|
||||
"---How to use Palmr.---",
|
||||
"manage-users",
|
||||
"uploading-files",
|
||||
@@ -25,4 +26,4 @@
|
||||
"gh-sponsor",
|
||||
"..."
|
||||
]
|
||||
}
|
||||
}
|
232
apps/docs/content/docs/3.0-beta/api.mdx
Normal file
@@ -0,0 +1,232 @@
|
||||
---
|
||||
title: API Endpoints
|
||||
icon: Plug
|
||||
---
|
||||
|
||||
Palmr. provides a comprehensive, well-documented, and fully typed REST API designed for maximum developer productivity and seamless integration. Whether you're building custom applications, automating workflows, or integrating with third-party services, our API offers the flexibility and reliability you need.
|
||||
|
||||
> **Overview:** The API is built with Fastify + Zod + TypeScript, ensuring type safety, schema validation, and excellent performance for all operations.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
### Exposing the API port
|
||||
|
||||
To access the API endpoints, you need to expose port **3333** in your Docker configuration. This port is where the Palmr. API server runs.
|
||||
|
||||
**Using Docker Compose:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
image: kyantech/palmr:latest
|
||||
ports:
|
||||
- "5487:5487" # Web interface
|
||||
- "3333:3333" # API port (required for API access)
|
||||
# ... other configuration
|
||||
```
|
||||
|
||||
**Using Docker run command:**
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name palmr \
|
||||
-e ENABLE_S3=false \
|
||||
-e ENCRYPTION_KEY=change-this-key-in-production-min-32-chars \
|
||||
-p 5487:5487 \
|
||||
-p 3333:3333 \
|
||||
-v palmr_data:/app/server \
|
||||
--restart unless-stopped \
|
||||
kyantech/palmr:latest
|
||||
```
|
||||
|
||||
> **Note:** Port 3333 exposure is optional if you only need the web interface. However, it's required for direct API access, custom integrations, and accessing the interactive documentation.
|
||||
|
||||
## Accessing the API documentation
|
||||
|
||||
The API documentation is available through interactive interfaces that allow you to explore, test, and validate all available endpoints directly in your browser.
|
||||
|
||||
### Documentation endpoints
|
||||
|
||||
**Local development:**
|
||||
|
||||
- Scalar documentation: `http://localhost:3333/docs`
|
||||
- Swagger documentation: `http://localhost:3333/swagger`
|
||||
|
||||
**Production environment:**
|
||||
|
||||
- Scalar documentation: `{your_domain}:3333/docs`
|
||||
- Swagger documentation: `{your_domain}:3333/swagger`
|
||||
|
||||
> **Important:** We don't provide an online version of the API documentation because endpoints and functionality may vary between different versions of Palmr. Always access the documentation from your specific deployment to ensure accuracy.
|
||||
|
||||
## Interactive documentation with Scalar
|
||||
|
||||
Our primary API documentation is powered by **Scalar**, a modern documentation platform that provides an exceptional developer experience.
|
||||
|
||||

|
||||
|
||||
### Why Scalar?
|
||||
|
||||
- **Interactive testing** - Test endpoints directly in the documentation
|
||||
- **Real-time validation** - Immediate feedback on request/response formats
|
||||
- **Modern interface** - Clean, intuitive design optimized for developer productivity
|
||||
- **Type-safe integration** - Full TypeScript support with automatic type inference
|
||||
- **Schema visualization** - Clear representation of request and response structures
|
||||
|
||||
### Key features
|
||||
|
||||
- **Comprehensive endpoint coverage** - All API endpoints documented with examples
|
||||
- **Authentication testing** - Built-in support for JWT token authentication
|
||||
- **Request builders** - Interactive forms for constructing API requests
|
||||
- **Response visualization** - Formatted display of API responses with syntax highlighting
|
||||
- **Code generation** - Generate client code in multiple programming languages
|
||||
|
||||
## Alternative Swagger documentation
|
||||
|
||||
For developers who prefer Swagger or need compatibility with existing tools, we also provide a Swagger-based documentation interface.
|
||||
|
||||

|
||||
|
||||
### When to use Swagger
|
||||
|
||||
- **Legacy tool compatibility** - Integration with existing Swagger-based workflows
|
||||
- **Team preferences** - When your team is more familiar with Swagger interface
|
||||
- **OpenAPI specification** - Direct access to OpenAPI spec for code generation
|
||||
- **Third-party integrations** - Tools that specifically require Swagger format
|
||||
|
||||
Both documentation formats provide identical endpoint coverage and functionality, ensuring you can choose the interface that best fits your development workflow.
|
||||
|
||||
## API capabilities
|
||||
|
||||
The Palmr. API provides comprehensive access to all platform features:
|
||||
|
||||
### File operations
|
||||
|
||||
- **Upload files** - Single and batch file uploads with progress tracking
|
||||
- **Download files** - Secure file retrieval with access control
|
||||
- **File management** - Rename, delete, and organize files
|
||||
- **Metadata access** - Retrieve file information and properties
|
||||
|
||||
### Share management
|
||||
|
||||
- **Create shares** - Generate public links for file sharing
|
||||
- **Configure access** - Set passwords, expiration dates, and view limits
|
||||
- **Track usage** - Monitor share views and download statistics
|
||||
- **Manage recipients** - Add and remove share recipients
|
||||
|
||||
### User operations
|
||||
|
||||
- **Authentication** - Login, logout, and session management
|
||||
- **Profile management** - Update user information and preferences
|
||||
- **User administration** - Create and manage user accounts (admin only)
|
||||
|
||||
### System integration
|
||||
|
||||
- **Health checks** - Monitor system status and availability
|
||||
- **Configuration** - Access and modify system settings
|
||||
- **Storage operations** - Manage filesystem and S3 storage options
|
||||
|
||||
## Authentication
|
||||
|
||||
The API uses **HTTP-only cookies** for secure authentication. After logging in through the web interface or API, authentication is automatically handled via secure cookies:
|
||||
|
||||
```bash
|
||||
# Login to establish authenticated session
|
||||
POST /auth/login
|
||||
{
|
||||
"email": "user@example.com",
|
||||
"password": "your-password"
|
||||
}
|
||||
|
||||
# Subsequent requests automatically include authentication cookies
|
||||
# No Authorization header needed - cookies are sent automatically
|
||||
GET /api/files
|
||||
```
|
||||
|
||||
### How authentication works
|
||||
|
||||
1. **Login** - Use the `/auth/login` endpoint with your credentials
|
||||
2. **Cookie storage** - The server sets HTTP-only cookies containing JWT tokens
|
||||
3. **Automatic authentication** - All subsequent API requests include these cookies automatically
|
||||
4. **Session management** - Cookies handle session persistence and expiration
|
||||
|
||||
### Security features
|
||||
|
||||
- **HTTP-only cookies** - Tokens stored securely in HTTP-only cookies, preventing XSS attacks
|
||||
- **Secure transmission** - Cookies marked as secure and same-site for enhanced protection
|
||||
- **Token expiration** - Automatic session timeout for security
|
||||
- **Role-based access** - Different permissions for users and administrators
|
||||
- **Request validation** - All inputs validated using Zod schemas
|
||||
|
||||
## Getting started with the API
|
||||
|
||||
### 1. Expose the API port
|
||||
|
||||
Ensure port 3333 is exposed in your Docker configuration to access the API endpoints.
|
||||
|
||||
### 2. Access the documentation
|
||||
|
||||
Visit your Palmr. instance at `:3333/docs` to explore the interactive API documentation.
|
||||
|
||||
### 3. Authenticate
|
||||
|
||||
Use the login endpoint to establish an authenticated session. Authentication cookies will be automatically set and included in subsequent requests.
|
||||
|
||||
### 4. Test endpoints
|
||||
|
||||
Use the interactive documentation to test API endpoints and understand request/response formats.
|
||||
|
||||
### 5. Build your integration
|
||||
|
||||
Implement your custom application using the API endpoints that match your requirements.
|
||||
|
||||
## Integration examples
|
||||
|
||||
The API enables powerful integrations and automation:
|
||||
|
||||
**Workflow automation:**
|
||||
|
||||
- Automatically upload files from CI/CD pipelines
|
||||
- Create shares for build artifacts and reports
|
||||
- Integrate with project management tools
|
||||
|
||||
**Custom applications:**
|
||||
|
||||
- Build mobile apps with native file management
|
||||
- Create specialized interfaces for specific use cases
|
||||
- Develop backup and sync solutions
|
||||
|
||||
**Business integrations:**
|
||||
|
||||
- Connect with existing document management systems
|
||||
- Automate file sharing workflows
|
||||
- Integrate with CRM and ERP systems
|
||||
|
||||
## Best practices
|
||||
|
||||
### Performance optimization
|
||||
|
||||
- **Use appropriate HTTP methods** - GET for retrieval, POST for creation, etc.
|
||||
- **Implement pagination** - Handle large datasets efficiently
|
||||
- **Cache responses** - Store frequently accessed data locally
|
||||
- **Batch operations** - Group multiple operations when possible
|
||||
|
||||
### Error handling
|
||||
|
||||
- **Check status codes** - Handle different HTTP response codes appropriately
|
||||
- **Parse error messages** - Use detailed error information for debugging
|
||||
- **Implement retries** - Handle temporary failures gracefully
|
||||
- **Log API interactions** - Maintain audit trails for troubleshooting
|
||||
|
||||
### Security considerations
|
||||
|
||||
- **Use HTTPS** - Always encrypt API communications to protect authentication cookies
|
||||
- **Secure cookies** - Authentication handled automatically via HTTP-only cookies
|
||||
- **Validate inputs** - Sanitize data before sending to API
|
||||
- **Monitor usage** - Track API calls for unusual activity
|
||||
|
||||
## Useful links
|
||||
|
||||
- [Scalar Official Website](https://scalar.com/) - Learn more about our primary documentation platform
|
||||
- [Swagger Official Website](https://swagger.io/) - Information about the alternative documentation format
|
||||
- [JWT.io](https://jwt.io/) - Understanding JSON Web Tokens for authentication
|
136
apps/docs/content/docs/3.0-beta/architecture.mdx
Normal file
@@ -0,0 +1,136 @@
|
||||
---
|
||||
title: Architecture of Palmr.
|
||||
icon: ServerCog
|
||||
---
|
||||
|
||||
import { ZoomableImage } from "@/components/ui/zoomable-image";
|
||||
|
||||
## Overview
|
||||
|
||||
Understanding the architecture of Palmr. is crucial for both deploying and scaling the application. The platform is designed with simplicity and flexibility in mind, offering a streamlined setup that can grow with your needs.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/architecture/architecture.png"
|
||||
alt="Palmr. Architecture"
|
||||
/>
|
||||
|
||||
## Technologies used
|
||||
|
||||
Each component in the Palmr. architecture plays a vital role in ensuring reliability, performance, and scalability. The stack is built with simplicity, performance, and flexibility in mind - everything is self-hosted, developer-friendly, and designed to scale without adding unnecessary complexity.
|
||||
|
||||
### SQLite + Prisma ORM
|
||||
|
||||
Palmr. uses **SQLite** as the primary database solution combined with **Prisma ORM** for type-safe database operations. SQLite is a lightweight, serverless database that's perfect for getting started quickly while still being powerful enough for production use. SQLite is fully ACID-compliant, which means it handles transactions safely and reliably. Prisma provides a modern database toolkit that generates a type-safe client, handles migrations, and offers an intuitive query API. Together, they create a powerful combination that eliminates database administration complexity while providing excellent developer experience.
|
||||
|
||||
- Provides reliable and secure data storage with zero configuration required
|
||||
- **Prisma ORM** offers type-safe queries and automatic TypeScript integration
|
||||
- Lightweight and fast, perfect for both development and production environments
|
||||
- Fully ACID-compliant with excellent performance for metadata and transactional data
|
||||
- Self-contained with no external dependencies or server processes needed
|
||||
- Easy database migrations and schema management through Prisma
|
||||
|
||||
### Next.js 15 + React + TypeScript
|
||||
|
||||
The frontend of Palmr. is built using **Next.js 15**, along with **React** and **TypeScript**, forming a modern stack that's easy to maintain and super fast for end users. Next.js 15 brings server components, server actions, and a new app router system that makes rendering dynamic content incredibly efficient. This allows us to load only what's needed, when it's needed - which makes the app feel snappy even under load. React provides a clean, component-based structure that makes it easy to break the UI into reusable pieces, and TypeScript helps prevent bugs before they even happen by enforcing static typing and better code navigation.
|
||||
|
||||
- **React** enables the creation of a dynamic and responsive user interface with a component-based architecture
|
||||
- **TypeScript** adds static typing, enhancing code quality and reducing runtime errors
|
||||
- **Next.js 15** handles routing, server-side rendering, and server components for performance at scale
|
||||
|
||||
### Filesystem storage
|
||||
|
||||
Palmr. uses **filesystem storage** as the default storage solution, keeping things simple and efficient. Files are organized in a structured directory layout on the local filesystem, making it easy to understand, backup, and manage. This approach eliminates external dependencies and provides excellent performance for most use cases. The system also supports **S3-compatible object storage** as an optional alternative for users who need cloud storage or additional scalability features.
|
||||
|
||||
- Simple and reliable file storage with organized directory structure
|
||||
- No external dependencies required for basic operation
|
||||
- Excellent performance for local file operations
|
||||
- Optional S3-compatible storage support for cloud deployments and scalability
|
||||
|
||||
### Fastify + Zod + TypeScript
|
||||
|
||||
The backend of Palmr. is powered by **Fastify**, **Zod**, and **TypeScript**, creating a robust and type-safe API layer. Fastify is a super-fast Node.js web framework optimized for performance and low overhead, designed to handle lots of concurrent requests with minimal resource usage. Zod provides runtime type validation and schema definition, ensuring all incoming data is properly validated before reaching business logic. TypeScript adds compile-time type safety throughout the entire backend codebase. This combination creates a highly reliable and maintainable backend that prevents bugs and security issues while maintaining excellent performance.
|
||||
|
||||
- **Fastify** provides fast request handling with a lightweight core
|
||||
- **Zod** enables runtime schema validation and type inference
|
||||
- **TypeScript** ensures type safety across the entire backend codebase
|
||||
- Built-in schema-based validation for secure and reliable API handling
|
||||
- Supports plugin-based architecture for easy extensibility
|
||||
- Optimized for high performance with minimal resource usage
|
||||
|
||||
## How it works
|
||||
|
||||
The Palmr. architecture follows a clean separation of concerns, making it easy to understand and maintain:
|
||||
|
||||
1. **Frontend** — React + TypeScript + Next.js 15 handle the user interface and user interactions
|
||||
2. **Backend** — Fastify + Zod + TypeScript process requests with full type safety and validation
|
||||
3. **Database** — SQLite + Prisma ORM store and manage data with type-safe operations
|
||||
4. **File Storage** — Filesystem storage handles file operations with optional S3-compatible support
|
||||
|
||||
## API integration and extensibility
|
||||
|
||||
One of Palmr.'s key strengths is its **open API architecture**, designed to integrate seamlessly with existing workflows and third-party services. The API can be exposed publicly, allowing for powerful integrations and custom development opportunities.
|
||||
|
||||
### Open API endpoints
|
||||
|
||||
Palmr. provides comprehensive REST API endpoints that can be integrated with various services and platforms:
|
||||
|
||||
**Popular integration possibilities:**
|
||||
|
||||
- **Zapier** - Automate file sharing workflows and connect with 5,000+ apps
|
||||
- **Microsoft Power Automate** - Create automated workflows within Microsoft ecosystem
|
||||
- **IFTTT** - Simple automation for personal and business use cases
|
||||
- **n8n** - Self-hosted workflow automation for advanced users
|
||||
- **GitHub Actions** - Integrate file sharing into CI/CD pipelines
|
||||
- **Slack/Discord Bots** - Share files directly from chat platforms
|
||||
- **Mobile Apps** - Build custom mobile applications using the API
|
||||
- **Desktop Applications** - Create native desktop clients for specific use cases
|
||||
|
||||
### Custom development opportunities
|
||||
|
||||
The open API architecture enables developers to:
|
||||
|
||||
- **Build custom clients** - Create specialized interfaces for specific industries or use cases
|
||||
- **Develop integrations** - Connect Palmr. with existing business systems and workflows
|
||||
- **Create automation scripts** - Automate repetitive file management tasks
|
||||
- **Build mobile apps** - Develop native iOS/Android applications
|
||||
- **Integrate with CMS** - Connect content management systems for seamless file handling
|
||||
- **Create backup solutions** - Build automated backup and sync tools
|
||||
|
||||
### API benefits
|
||||
|
||||
- **RESTful design** - Standard HTTP methods and status codes for easy integration
|
||||
- **Comprehensive documentation** - Complete API reference with examples and use cases
|
||||
- **Authentication support** - Secure API access with JWT token-based authentication
|
||||
- **Schema validation** - Built-in request/response validation using Zod schemas
|
||||
- **Type safety** - Full TypeScript support for reliable integrations
|
||||
- **Bulk operations** - Efficient handling of multiple files and batch operations
|
||||
|
||||
This open architecture makes Palmr. not just a file-sharing platform, but a **file management ecosystem** that can adapt to any workflow or business requirement. Whether you're a developer looking to integrate file sharing into your application or a business wanting to automate file workflows, Palmr.'s API provides the flexibility and power you need.
|
||||
|
||||
## Storage flexibility
|
||||
|
||||
Palmr. is designed to be flexible in how you handle file storage:
|
||||
|
||||
**Default setup (Filesystem):**
|
||||
|
||||
- Files stored directly on the local filesystem
|
||||
- Simple directory structure for easy management
|
||||
- Perfect for single-server deployments and development
|
||||
- No additional configuration required
|
||||
|
||||
**Optional S3-compatible storage:**
|
||||
|
||||
- Enable S3 storage by setting `ENABLE_S3=true`, look at [S3 Providers](/docs/3.0-beta/s3-providers) for more information.
|
||||
- Compatible with AWS S3, MinIO, and other S3-compatible services
|
||||
- Ideal for cloud deployments and distributed setups
|
||||
- Provides additional scalability and redundancy options
|
||||
|
||||
## Useful links
|
||||
|
||||
- [SQLite Documentation](https://www.sqlite.org/docs.html)
|
||||
- [Prisma Documentation](https://www.prisma.io/docs)
|
||||
- [Next.js Documentation](https://nextjs.org/docs)
|
||||
- [React Documentation](https://react.dev/)
|
||||
- [TypeScript Handbook](https://www.typescriptlang.org/docs/)
|
||||
- [Fastify Documentation](https://fastify.dev/docs/latest/)
|
||||
- [Zod Documentation](https://zod.dev/)
|
66
apps/docs/content/docs/3.0-beta/available-languages.mdx
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Available Languages
|
||||
icon: Globe
|
||||
---
|
||||
|
||||
The project leverages next-intl, a powerful and flexible internationalization (i18n) library, to provide comprehensive language support across the entire application. This robust solution enables seamless translation management, date/time formatting, number formatting, and pluralization rules across different locales.
|
||||
|
||||
The integration of next-intl ensures consistent internationalization throughout the application's components, pages, and features, while maintaining optimal performance through efficient bundle splitting and lazy loading of language resources. With its TypeScript support and React Server Components compatibility, next-intl serves as the foundation for delivering a truly global and accessible user experience.
|
||||
|
||||
## Supported languages
|
||||
|
||||
Palmr currently supports 15 languages with complete translations across all application features and interfaces.
|
||||
|
||||
---
|
||||
|
||||
| Language | Code | Description | Translation |
|
||||
| -------------------- | ----- | -------------------------------------------------------- | ----------- |
|
||||
| English | en-US | Primary development language and default fallback option | 100% |
|
||||
| Portuguese | pt-BR | Standard Brazilian Portuguese support | 100% |
|
||||
| French | fr-FR | Standard French language support | 100% |
|
||||
| Spanish | es-ES | Standard Spanish language support | 100% |
|
||||
| German | de-DE | Standard German language support | 100% |
|
||||
| Russian | ru-RU | Standard Russian language support | 100% |
|
||||
| Hindi | hi-IN | Standard Hindi language support | 100% |
|
||||
| Arabic | ar-SA | Standard Arabic language support with RTL | 100% |
|
||||
| Japanese | ja-JP | Standard Japanese language support | 100% |
|
||||
| Korean | ko-KR | Standard Korean language support | 100% |
|
||||
| Turkish | tr-TR | Standard Turkish language support | 100% |
|
||||
| Chinese (Simplified) | zh-CN | Standard Simplified Chinese support | 100% |
|
||||
| Italian | it-IT | Standard Italian language support | 100% |
|
||||
| Dutch | nl-NL | Standard Dutch language support | 100% |
|
||||
| Polish | pl-PL | Standard Polish language support | 100% |
|
||||
|
||||
## Language selection
|
||||
|
||||
The application provides two convenient methods for language selection, ensuring a seamless user experience across different user preferences and scenarios.
|
||||
|
||||
### Automatic detection
|
||||
|
||||
The application features sophisticated automatic detection of the user's preferred browser language settings. It intelligently utilizes the browser's preconfigured language preferences to set the initial application language, providing an immediate localized experience without requiring user intervention.
|
||||
|
||||
### Manual selection
|
||||
|
||||

|
||||
|
||||
Users have complete control to manually select their preferred language through an intuitive language selector interface in the UI. The language selector is easily accessible and provides immediate language switching capabilities.
|
||||
|
||||
Selected language preferences are persistently stored in the browser's localStorage, ensuring a consistent experience across sessions and eliminating the need to reselect languages on subsequent visits.
|
||||
|
||||
## Default language
|
||||
|
||||
English (en-US) serves as the system's fallback language, ensuring consistent functionality even when language detection or selection encounters issues. This means that if a user's preferred language is not available or if there are any problems with language selection, the application will automatically default to English.
|
||||
|
||||
This fallback mechanism is crucial for maintaining a seamless user experience and preventing any potential language-related disruptions. Additionally, all new features and updates are first implemented in English before being translated into other supported languages, ensuring that the English version always remains the most up-to-date and comprehensive.
|
||||
|
||||
## Language detection
|
||||
|
||||
The application employs advanced detection mechanisms to automatically identify and apply the user's browser language settings as the initial language configuration. This process analyzes the browser's language preferences and matches them against available translations.
|
||||
|
||||
For maximum flexibility, users can easily override this automatic selection at any time using the convenient language switcher, accessible via the globe icon prominently displayed in the navigation bar.
|
||||
|
||||
## RTL support
|
||||
|
||||
The application incorporates comprehensive right-to-left (RTL) text handling capabilities, with particular attention paid to Arabic (ar-SA) language requirements. This includes proper text alignment, layout direction, and user interface elements that adapt to RTL reading patterns.
|
||||
|
||||
RTL support ensures that Arabic-speaking users receive a native and intuitive experience, with all interface elements properly oriented and text flowing in the correct direction for optimal readability and usability.
|
148
apps/docs/content/docs/3.0-beta/configuring-smtp.mdx
Normal file
@@ -0,0 +1,148 @@
|
||||
---
|
||||
title: Configuring SMTP
|
||||
icon: Mail
|
||||
---
|
||||
|
||||
For Palmr to function with all its best features, you need to configure an email server. To make this process easier, there's a built-in configuration panel inside **Settings** in Palmr. However, only users with an **ADMIN** profile can access and configure these settings.
|
||||
|
||||
This guide walks you through the complete process of setting up SMTP for your Palmr installation, ensuring that email-dependent features work seamlessly.
|
||||
|
||||
## Why configure SMTP?
|
||||
|
||||
Configuring SMTP is essential for enabling key email functionalities that enhance the user experience and ensure proper system operation.
|
||||
|
||||
The main functionalities that depend on SMTP configuration are:
|
||||
|
||||
- **Password Reset** – Users who forget their password and cannot access the **Settings** panel need this feature to regain access to their accounts.
|
||||
- **Email Notifications** – Recipients will receive email notifications when new shares are sent to them, keeping them informed about shared content.
|
||||
|
||||
Without proper SMTP configuration, these features will not work, potentially leaving users unable to recover their accounts or stay informed about shared files.
|
||||
|
||||
Now, let's go through the step-by-step process to configure the **SMTP Server**.
|
||||
|
||||
---
|
||||
|
||||
## Accessing SMTP settings
|
||||
|
||||
To configure SMTP settings, you'll need administrative access to the Palmr settings panel.
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before beginning the configuration process:
|
||||
|
||||
- Ensure you have **ADMIN** user privileges in Palmr
|
||||
- Have your SMTP server credentials ready
|
||||
- For Gmail users, prepare to generate an App Password
|
||||
|
||||
### Navigating to settings
|
||||
|
||||
To access **Settings**, an **ADMIN** user must click on the profile picture in the **header** and select **Settings** from the dropdown menu.
|
||||
|
||||

|
||||
|
||||
Once inside the **Settings** panel, click on the **Email** card to expand the SMTP configuration options.
|
||||
|
||||

|
||||
|
||||
After expanding the card, the following SMTP configuration fields will appear:
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Configuring SMTP server
|
||||
|
||||
The SMTP configuration process involves enabling the service and configuring the necessary connection details.
|
||||
|
||||
### Enabling SMTP
|
||||
|
||||
The first step is to **enable SMTP** by selecting "Yes" in the **SMTP Enabled** field.
|
||||
|
||||

|
||||
|
||||
### Configuration fields
|
||||
|
||||
Once SMTP is enabled, you can configure the other necessary fields:
|
||||
|
||||
**Sender Name** – This will appear as the sender's name in all outgoing emails. Use a recognizable name like "Palmr" or your organization name.
|
||||
|
||||
**Sender Email** – The email address from which notifications will be sent. Use a professional address like "noreply@palmr.app" or "notifications@yourdomain.com".
|
||||
|
||||
**SMTP Server** – The SMTP server address provided by your email service. For Gmail, use `smtp.gmail.com` (this is the recommended option and set as default).
|
||||
|
||||
**SMTP Port** – The server port used for connections. For Gmail, the standard port is **587** (TLS encryption).
|
||||
|
||||
**SMTP Username** – The username for authenticating with your SMTP server. For Gmail, enter your complete email address.
|
||||
|
||||
**SMTP Password** – The password for SMTP authentication. For Gmail, you must use an **App Password** (not your regular email password).
|
||||
|
||||
### Important security note
|
||||
|
||||
**Important:** If using **Gmail**, you need to generate an **App Password** instead of using your standard email password. This provides better security and is required for applications like Palmr.
|
||||
|
||||
For other email services, consult the official documentation of the service provider you are using. We recommend using Gmail for its simplicity, reliability, and reasonable email sending limits.
|
||||
|
||||
---
|
||||
|
||||
## Generating a Gmail App Password
|
||||
|
||||
Gmail requires App Passwords for third-party applications to ensure account security while maintaining functionality.
|
||||
|
||||
### Step-by-step process
|
||||
|
||||
To generate an App Password for Gmail:
|
||||
|
||||
1. **Access Your Account**: Go to [Google My Account](https://myaccount.google.com/)
|
||||
2. **Navigate to Security**: Select the **Security** section from the menu
|
||||
3. **Find App Passwords**: Scroll down to locate **App Passwords** (you may need to enable 2-factor authentication first)
|
||||
4. **Generate Password**: Create a new password specifically for Palmr
|
||||
5. **Save Securely**: Copy and store the generated password safely
|
||||
|
||||
### Additional resources
|
||||
|
||||
For a complete guide with screenshots and detailed instructions, refer to: **[How to set up SMTP credentials with Gmail](https://medium.com/rails-to-rescue/how-to-set-up-smtp-credentials-with-gmail-for-your-app-send-email-cf236d11087d)**.
|
||||
|
||||
### Gmail configuration summary
|
||||
|
||||
When using Gmail, your final settings should be:
|
||||
|
||||
- **SMTP Server**: `smtp.gmail.com`
|
||||
- **SMTP Port**: `587`
|
||||
- **SMTP Username**: Your Gmail address
|
||||
- **SMTP Password**: Generated App Password (16 characters)
|
||||
|
||||
---
|
||||
|
||||
## Testing your configuration
|
||||
|
||||
After completing the configuration, it's important to verify that everything works correctly.
|
||||
|
||||
### Validation steps
|
||||
|
||||
1. **Save Settings**: Apply your SMTP configuration in the Palmr interface
|
||||
2. **Test Password Reset**: Try the password reset feature with a test account to ensure emails are sent
|
||||
3. **Test Notifications**: Create a test share to verify that notification emails are delivered
|
||||
4. **Check Email Delivery**: Confirm that emails arrive in the recipient's inbox (not spam folder)
|
||||
|
||||
### Troubleshooting common issues
|
||||
|
||||
If emails are not being sent:
|
||||
|
||||
- Verify that all fields are filled correctly
|
||||
- For Gmail, ensure you're using the App Password, not your regular password
|
||||
- Check that your email provider allows SMTP connections
|
||||
- Confirm that port 587 is not blocked by your firewall
|
||||
|
||||
---
|
||||
|
||||
## Finalizing SMTP configuration
|
||||
|
||||
After entering the correct information and testing the functionality, save the settings.
|
||||
|
||||
Your Palmr installation is now ready to:
|
||||
|
||||
- Send password reset emails to users who need account recovery
|
||||
- Deliver share notifications to recipients automatically
|
||||
- Provide a complete user experience with reliable email communication
|
||||
|
||||
With SMTP properly configured, users can take full advantage of Palmr's email-dependent features, ensuring a smooth and professional experience when sharing files and managing their accounts.
|
442
apps/docs/content/docs/3.0-beta/contribute.mdx
Normal file
@@ -0,0 +1,442 @@
|
||||
---
|
||||
title: How to Contribute
|
||||
icon: Users
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Thank you for your interest in contributing to the **Palmr** project! Contributions are what make the open-source community such an amazing place to learn, inspire, and create. Whether you're fixing bugs, adding new features, improving documentation, or sharing ideas, every contribution helps make Palmr better for everyone.
|
||||
|
||||
We welcome contributors of all experience levels - from beginners to seasoned developers. This comprehensive guide will walk you through the process of contributing to Palmr, from setting up your development environment to submitting your first pull request.
|
||||
|
||||
We're excited to have you join our community of contributors and look forward to seeing what you'll bring to the project.
|
||||
|
||||
---
|
||||
|
||||
## GitHub account requirements
|
||||
|
||||
Before you can contribute, you'll need to be logged into your GitHub account. If you don't have an account yet, creating one is free and opens up the entire world of open-source collaboration.
|
||||
|
||||
### Account setup benefits
|
||||
|
||||
Having a GitHub account is essential as it allows you to:
|
||||
|
||||
- Fork repositories and create your own copies
|
||||
- Submit pull requests to propose changes
|
||||
- Interact with other contributors and maintainers
|
||||
- Track issues and participate in discussions
|
||||
- Build your open-source portfolio
|
||||
|
||||
### Security recommendations
|
||||
|
||||
When creating your account:
|
||||
|
||||
- Use a professional email address for your GitHub account
|
||||
- Enable two-factor authentication for enhanced security
|
||||
- Customize your profile to showcase your interests and skills
|
||||
- Explore the GitHub community to discover other projects
|
||||
|
||||
If you need to create an account, visit [GitHub's signup page](https://github.com/signup) and follow the registration process.
|
||||
|
||||
---
|
||||
|
||||
## Accessing the repository
|
||||
|
||||
Once you're logged into your GitHub account, you'll need to navigate to the Palmr repository to begin your contribution journey.
|
||||
|
||||
### Direct access
|
||||
|
||||
Visit the Palmr repository directly: [https://github.com/kyantech/Palmr](https://github.com/kyantech/Palmr)
|
||||
|
||||
The repository contains all the source code, documentation, and resources for the Palmr project. Take time to explore the repository structure, including the README file, which provides an overview of the project.
|
||||
|
||||
### Alternative access methods
|
||||
|
||||
You can also find the repository by:
|
||||
|
||||
- Searching for "Palmr" in the GitHub search bar
|
||||
- Looking for the repository owned by **kyantech**
|
||||
- Accessing it through Kyantech's organization page
|
||||
|
||||
### Repository verification
|
||||
|
||||
When searching, ensure you're accessing the official repository by:
|
||||
|
||||
- Checking the owner and repository name match exactly
|
||||
- Verifying the description matches the Palmr project
|
||||
- Confirming recent activity from the maintainers
|
||||
- Reviewing the number of stars, forks, and watchers
|
||||
|
||||
---
|
||||
|
||||
## Forking the repository
|
||||
|
||||
To contribute to the project, you'll need to create your own copy of the repository. This process is called **forking** and is fundamental to the GitHub collaboration workflow.
|
||||
|
||||
### Creating your fork
|
||||
|
||||
Here's how to fork the repository:
|
||||
|
||||
1. **Locate the Fork Button**: Click the **Fork** button at the top right of the repository page
|
||||
2. **Select Destination**: Choose where you want to fork the repository (your personal account or an organization)
|
||||
3. **Wait for Creation**: Allow a few moments while GitHub creates your fork
|
||||
4. **Automatic Redirect**: You'll be redirected to your forked repository once it's ready
|
||||
|
||||
### Fork benefits
|
||||
|
||||
Your fork will maintain a connection to the original repository, allowing you to:
|
||||
|
||||
- Keep your fork synchronized with the original repository
|
||||
- Submit pull requests from your fork to the original repository
|
||||
- Work independently on your own copy without affecting the original
|
||||
- Experiment with changes before proposing them
|
||||
|
||||
---
|
||||
|
||||
## Cloning your fork
|
||||
|
||||
After forking the repository, you'll need to clone it to your local machine to begin making changes.
|
||||
|
||||
### Clone process
|
||||
|
||||
Follow these steps to clone your forked repository:
|
||||
|
||||
1. **Access Clone Options**: On your forked repository page, click the **Code** button
|
||||
2. **Copy Repository URL**: Copy the repository URL (HTTPS or SSH, depending on your preference)
|
||||
3. **Open Terminal**: Open your terminal or command prompt
|
||||
4. **Execute Clone Command**: Run the following command to clone the repository:
|
||||
|
||||
```bash
|
||||
git clone <repository-url>
|
||||
```
|
||||
|
||||
5. **Navigate to Directory**: Move into the cloned directory:
|
||||
|
||||
```bash
|
||||
cd Palmr
|
||||
```
|
||||
|
||||
### Clone verification
|
||||
|
||||
After cloning, verify your setup by:
|
||||
|
||||
- Confirming all files are present in your local directory
|
||||
- Checking that you can access the project files
|
||||
- Testing that Git is properly configured for the repository
|
||||
|
||||
---
|
||||
|
||||
## Setting up the base branch
|
||||
|
||||
Before making changes, ensure your local repository is properly configured to track the correct branch from the original Palmr repository.
|
||||
|
||||
### Remote configuration
|
||||
|
||||
Set up your repository to track the upstream repository:
|
||||
|
||||
1. **Add Upstream Remote**: Add the original Palmr repository as a remote:
|
||||
|
||||
```bash
|
||||
git remote add upstream https://github.com/kyantech/Palmr.git
|
||||
```
|
||||
|
||||
2. **Fetch Latest Changes**: Retrieve the latest changes from the `next` branch:
|
||||
|
||||
```bash
|
||||
git fetch upstream next
|
||||
```
|
||||
|
||||
3. **Create Feature Branch**: Create a new branch for your contribution based on `upstream/next`:
|
||||
|
||||
```bash
|
||||
git checkout -b your-branch-name upstream/next
|
||||
```
|
||||
|
||||
### Branch naming conventions
|
||||
|
||||
When creating your branch, use descriptive names that indicate the purpose of your changes:
|
||||
|
||||
- `feature/user-authentication` for new features
|
||||
- `fix/login-bug` for bug fixes
|
||||
- `docs/api-documentation` for documentation updates
|
||||
- `refactor/database-queries` for code improvements
|
||||
|
||||
---
|
||||
|
||||
## Making your changes
|
||||
|
||||
Now you're ready to implement your contributions! This is where your creativity and technical skills come into play.
|
||||
|
||||
### Types of contributions
|
||||
|
||||
Your contributions could include:
|
||||
|
||||
- **Bug Fixes**: Resolving issues and improving stability
|
||||
- **New Features**: Adding functionality that enhances the project
|
||||
- **Documentation**: Improving guides, API docs, and examples
|
||||
- **Testing**: Writing or improving test coverage
|
||||
- **Performance**: Optimizing code for better efficiency
|
||||
- **Accessibility**: Making the project more inclusive
|
||||
- **Translations**: Adding support for different languages
|
||||
- **Code Quality**: Refactoring and improving code structure
|
||||
|
||||
### Development best practices
|
||||
|
||||
When making changes, follow these guidelines:
|
||||
|
||||
1. **Follow Style Guidelines**: Ensure your code adheres to the project's coding standards
|
||||
2. **Test Incrementally**: Run tests locally to catch issues early
|
||||
3. **Keep Changes Focused**: Address a single issue or feature per contribution
|
||||
4. **Document Changes**: Update or add documentation as needed
|
||||
5. **Review Your Work**: Double-check changes before committing
|
||||
|
||||
### Development workflow
|
||||
|
||||
Maintain a productive workflow by:
|
||||
|
||||
- Regularly saving your work and committing small, logical changes
|
||||
- Testing your changes incrementally to identify issues quickly
|
||||
- Keeping your branch updated with the latest upstream changes
|
||||
- Seeking feedback early if you're unsure about your approach
|
||||
|
||||
---
|
||||
|
||||
## Using conventional commits
|
||||
|
||||
Once you've made your changes, commit them using **Conventional Commits** format. This standard helps maintain a clean and consistent commit history that's easy to understand and automate.
|
||||
|
||||
### Commit message format
|
||||
|
||||
Structure your commit messages as follows:
|
||||
|
||||
`<type>(<scope>): <description>`
|
||||
|
||||
### Commit types and examples
|
||||
|
||||
**Common commit types:**
|
||||
|
||||
- `feat: add user authentication system`
|
||||
- `fix(api): resolve null pointer exception in user service`
|
||||
- `docs: update installation instructions in README`
|
||||
- `test: add unit tests for user validation`
|
||||
- `refactor: simplify database connection logic`
|
||||
- `style: fix code formatting in auth module`
|
||||
- `chore: update project dependencies`
|
||||
|
||||
### Committing your changes
|
||||
|
||||
Follow these steps to commit your work:
|
||||
|
||||
1. **Stage Changes**: Add your changes to the staging area:
|
||||
|
||||
```bash
|
||||
git add .
|
||||
```
|
||||
|
||||
2. **Commit with Message**: Create a commit with a properly formatted message:
|
||||
|
||||
```bash
|
||||
git commit -m "feat: add new feature for user profiles"
|
||||
```
|
||||
|
||||
### Commit best practices
|
||||
|
||||
- Write clear, concise commit messages
|
||||
- Use the imperative mood ("add" not "added")
|
||||
- Keep the first line under 50 characters
|
||||
- Include additional details in the body if necessary
|
||||
|
||||
---
|
||||
|
||||
## Pushing your changes
|
||||
|
||||
After committing your changes locally, you need to push them to your forked repository on GitHub to make them available for review.
|
||||
|
||||
### Push process
|
||||
|
||||
Synchronize your local changes with your remote repository:
|
||||
|
||||
1. **Check for Updates**: Ensure your branch is current with any remote changes:
|
||||
|
||||
```bash
|
||||
git pull origin your-branch-name
|
||||
```
|
||||
|
||||
2. **Push Commits**: Upload your commits to your forked repository:
|
||||
|
||||
```bash
|
||||
git push origin your-branch-name
|
||||
```
|
||||
|
||||
3. **Set Upstream** (first push only): If this is your first push for this branch:
|
||||
```bash
|
||||
git push -u origin your-branch-name
|
||||
```
|
||||
|
||||
### Troubleshooting push issues
|
||||
|
||||
If you encounter errors while pushing:
|
||||
|
||||
- Verify you have the correct permissions on your fork
|
||||
- Check your remote URL configuration using `git remote -v`
|
||||
- Ensure you're authenticated with GitHub properly
|
||||
- Confirm your branch name matches what you're trying to push
|
||||
|
||||
---
|
||||
|
||||
## Creating a pull request
|
||||
|
||||
With your changes pushed to GitHub, you can now create a **Pull Request (PR)** to propose your changes to the main Palmr repository.
|
||||
|
||||
### Pull request setup
|
||||
|
||||
Create your pull request by following these steps:
|
||||
|
||||
1. **Navigate to Your Fork**: Go to your forked repository on GitHub
|
||||
2. **Initiate PR**: Click the **Pull Request** button or **Compare & pull request** if available
|
||||
3. **Configure PR Settings**: On the PR creation page, set:
|
||||
- **Base repository**: `kyantech/Palmr`
|
||||
- **Base branch**: `next`
|
||||
- **Head repository**: Your forked repository
|
||||
- **Compare branch**: Your feature branch (`your-branch-name`)
|
||||
|
||||
### Pull request content
|
||||
|
||||
Fill out the PR form with comprehensive information:
|
||||
|
||||
- **Clear Title**: Write a descriptive title that summarizes your changes
|
||||
- **Detailed Description**: Explain what your changes do and why they're needed
|
||||
- **Related Issues**: Reference any issues your PR addresses
|
||||
- **Testing Information**: Describe how you tested your changes
|
||||
- **Screenshots**: Include visual evidence if your changes affect the UI
|
||||
|
||||
### PR checklist
|
||||
|
||||
Before submitting, ensure your PR:
|
||||
|
||||
- Has a clear, descriptive title
|
||||
- Includes a comprehensive description
|
||||
- References related issues
|
||||
- Follows the project's contribution guidelines
|
||||
- Includes appropriate tests
|
||||
- Updates documentation if necessary
|
||||
|
||||
---
|
||||
|
||||
## Awaiting review
|
||||
|
||||
Once your PR is submitted, the project maintainers will review your changes. This collaborative process ensures code quality and project consistency.
|
||||
|
||||
### Review process expectations
|
||||
|
||||
During the review process:
|
||||
|
||||
- **Monitor Notifications**: Keep an eye on GitHub notifications for comments or requests
|
||||
- **Respond Promptly**: Address feedback in a timely and professional manner
|
||||
- **Make Updates**: If changes are requested, update your branch and push new commits
|
||||
- **Ask Questions**: Don't hesitate to seek clarification if feedback is unclear
|
||||
- **Stay Patient**: Review times vary depending on maintainer availability and PR complexity
|
||||
|
||||
### Handling feedback
|
||||
|
||||
When receiving feedback:
|
||||
|
||||
- Approach it as a learning opportunity
|
||||
- Ask questions if you don't understand suggestions
|
||||
- Make requested changes promptly
|
||||
- Thank reviewers for their time and input
|
||||
- Stay engaged throughout the process
|
||||
|
||||
### Review timeline
|
||||
|
||||
Remember that:
|
||||
|
||||
- Maintainers are often volunteers with limited time
|
||||
- Complex changes may require multiple review rounds
|
||||
- The review process helps ensure high-quality contributions
|
||||
- Your patience and cooperation are appreciated
|
||||
|
||||
---
|
||||
|
||||
## Contribution best practices
|
||||
|
||||
To maximize the chances of your contribution being accepted, follow these proven practices:
|
||||
|
||||
### Code quality standards
|
||||
|
||||
- **Use Conventional Commits**: Maintain consistent commit message formatting
|
||||
- **Keep PRs Focused**: Address one issue or feature per pull request
|
||||
- **Write Comprehensive Tests**: Include tests for new features and bug fixes
|
||||
- **Follow Code Style**: Adhere to the project's coding standards and guidelines
|
||||
- **Update Documentation**: Keep documentation synchronized with code changes
|
||||
|
||||
### Collaboration guidelines
|
||||
|
||||
- **Engage Constructively**: Participate in PR discussions with a positive attitude
|
||||
- **Review Others' Work**: Help the community by reviewing other contributors' pull requests
|
||||
- **Stay Updated**: Keep your fork synchronized with the main repository
|
||||
- **Be Patient**: Understand that maintainers balance multiple responsibilities
|
||||
- **Communicate Clearly**: Express your ideas and questions clearly and respectfully
|
||||
|
||||
### Continuous improvement
|
||||
|
||||
- **Learn from Feedback**: Use review comments as opportunities to improve your skills
|
||||
- **Study the Codebase**: Understand the project structure and patterns before contributing
|
||||
- **Start Small**: Begin with minor contributions to familiarize yourself with the process
|
||||
- **Build Relationships**: Engage with the community to build lasting connections
|
||||
|
||||
---
|
||||
|
||||
## Why contribute to open source?
|
||||
|
||||
Contributing to open-source projects like Palmr offers numerous personal and professional benefits that extend far beyond the immediate code changes.
|
||||
|
||||
### Personal development
|
||||
|
||||
**Skill Building**: You'll gain hands-on experience with Git, GitHub, collaborative coding, and industry-standard development practices.
|
||||
|
||||
**Portfolio Enhancement**: Open-source contributions demonstrate your skills to potential employers and showcase your commitment to continuous learning.
|
||||
|
||||
**Problem-Solving**: Working on real-world projects helps you develop critical thinking and problem-solving abilities.
|
||||
|
||||
### Community impact
|
||||
|
||||
**Project Improvement**: Your contributions directly help make the project better for all users and contributors.
|
||||
|
||||
**Knowledge Sharing**: By contributing, you share your expertise and learn from others in the community.
|
||||
|
||||
**Ecosystem Support**: Open-source projects thrive on community contributions, and your work helps sustain the entire ecosystem.
|
||||
|
||||
### Professional benefits
|
||||
|
||||
**Networking**: Connect with developers, maintainers, and other contributors from around the world.
|
||||
|
||||
**Recognition**: Build your reputation in the developer community through quality contributions.
|
||||
|
||||
**Career Opportunities**: Many career opportunities arise from open-source involvement and community connections.
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
Congratulations! You now have all the knowledge needed to contribute effectively to the **Palmr** project. Your contributions, whether large or small, make a meaningful difference to the project and its community.
|
||||
|
||||
### Getting started
|
||||
|
||||
Ready to make your first contribution? Consider starting with:
|
||||
|
||||
- **Documentation improvements**: Fix typos, clarify instructions, or add examples
|
||||
- **Bug fixes**: Address issues reported by other users
|
||||
- **Feature enhancements**: Implement small improvements to existing functionality
|
||||
- **Test coverage**: Add tests to improve project reliability
|
||||
|
||||
### Staying engaged
|
||||
|
||||
Continue your involvement by:
|
||||
|
||||
- Following the project's progress and updates
|
||||
- Participating in community discussions
|
||||
- Helping other new contributors get started
|
||||
- Sharing your experience with the broader developer community
|
||||
|
||||
Thank you for your interest in contributing to Palmr. We look forward to seeing your contributions and welcoming you to our community of developers working together to make Palmr better for everyone.
|
179
apps/docs/content/docs/3.0-beta/gh-sponsor.mdx
Normal file
@@ -0,0 +1,179 @@
|
||||
---
|
||||
title: GitHub Sponsors
|
||||
icon: Heart
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Sponsoring a project on GitHub is a powerful way to support its development and ensure its long-term sustainability. This guide walks you through the process of sponsoring the **Palmr** project using GitHub Sponsors.
|
||||
|
||||
By becoming a sponsor, you directly contribute to the project's growth and help maintain its quality. Your sponsorship enables:
|
||||
|
||||
- Continuous development and timely bug fixes
|
||||
- Implementation of new features and improvements
|
||||
- Coverage of hosting and infrastructure costs
|
||||
- Recognition of the developers' dedication and hard work
|
||||
- Building a community of supporters who value open source development
|
||||
|
||||
---
|
||||
|
||||
## GitHub account requirements
|
||||
|
||||
Before you can sponsor a project, you'll need to be logged into your GitHub account. If you don't have an account yet, creating one is free and provides additional benefits beyond sponsorship.
|
||||
|
||||
### Account benefits
|
||||
|
||||
Having a GitHub account allows you to:
|
||||
|
||||
- Follow project updates and releases
|
||||
- Report issues and suggest improvements
|
||||
- Contribute to project discussions
|
||||
- Access sponsor-exclusive content when available
|
||||
- Participate in the broader GitHub community
|
||||
|
||||
If you need to create an account, visit [GitHub's signup page](https://github.com/signup) and follow the registration process.
|
||||
|
||||
---
|
||||
|
||||
## Accessing the repository
|
||||
|
||||
Once you're logged into your GitHub account, navigate to the Palmr repository to begin the sponsorship process.
|
||||
|
||||
### Direct access
|
||||
|
||||
Visit the Palmr repository directly: [https://github.com/kyantech/Palmr](https://github.com/kyantech/Palmr)
|
||||
|
||||
### Alternative methods
|
||||
|
||||
You can also find the repository by:
|
||||
|
||||
- Searching for "Palmr" in the GitHub search bar
|
||||
- Looking for the repository owned by **Kyantech**
|
||||
- Accessing it through Kyantech's profile page
|
||||
|
||||
### Additional repository actions
|
||||
|
||||
While you're on the repository page, consider:
|
||||
|
||||
- **Starring** the repository to show your support
|
||||
- **Watching** it to receive notifications about updates
|
||||
- **Forking** it if you're interested in contributing code
|
||||
|
||||
---
|
||||
|
||||
## Initiating sponsorship
|
||||
|
||||
The sponsorship process begins with locating and clicking the sponsor button on the repository page.
|
||||
|
||||
### Finding the sponsor button
|
||||
|
||||
On the Palmr repository page, you'll find a **Sponsor** button prominently displayed in the top section of the page. This button is typically highlighted in a distinct color to ensure visibility.
|
||||
|
||||

|
||||
|
||||
### Quick access
|
||||
|
||||
**Pro Tip**: If you've previously sponsored projects, you can access your sponsorship dashboard directly through your GitHub profile under the "Sponsoring" section.
|
||||
|
||||
---
|
||||
|
||||
## Selecting your sponsorship level
|
||||
|
||||
GitHub Sponsors offers flexible sponsorship options to accommodate different budgets and preferences.
|
||||
|
||||
### Custom sponsorship options
|
||||
|
||||
GitHub Sponsors allows you to sponsor the project with a **custom amount starting at $1**:
|
||||
|
||||
1. **Enter Custom Amount**: Look for the option to enter a custom sponsorship amount
|
||||
2. **Choose Your Amount**: Select any amount you're comfortable with (e.g., $1, $5, $10, or higher)
|
||||
3. **Select Billing Frequency**: Choose between **monthly** recurring sponsorship or **one-time** payment
|
||||
4. **Consider Annual Options**: Some projects offer simplified annual sponsorship plans
|
||||
5. **Review Tier Benefits**: Check for any special benefits available at different sponsorship levels
|
||||
|
||||

|
||||
|
||||
### Sponsorship recommendations
|
||||
|
||||
- **Monthly Sponsorship**: Provides consistent support for ongoing development
|
||||
- **One-time Sponsorship**: Perfect for showing appreciation for specific features or releases
|
||||
- **Higher Tiers**: May include additional benefits like early access or direct communication
|
||||
|
||||
---
|
||||
|
||||
## Completing your sponsorship
|
||||
|
||||
After selecting your sponsorship amount and billing preferences, you'll proceed to the payment process.
|
||||
|
||||
### Payment process
|
||||
|
||||
1. **Review Your Selection**: Confirm your sponsorship amount and billing frequency
|
||||
2. **Enter Payment Details**: Provide your payment information as prompted
|
||||
3. **Complete Transaction**: Follow GitHub's secure payment process
|
||||
4. **Confirmation**: Receive confirmation of your successful sponsorship
|
||||
|
||||
Once the process is complete, you'll officially become a **Palmr sponsor** and join our community of supporters.
|
||||
|
||||
---
|
||||
|
||||
## The impact of your sponsorship
|
||||
|
||||
Understanding why sponsorship matters helps illustrate the value of your contribution to the open source ecosystem.
|
||||
|
||||
### Project sustainability
|
||||
|
||||
**Long-term Maintenance**: Your sponsorship helps ensure the project remains actively maintained and supported over time.
|
||||
|
||||
**Innovation Support**: Financial backing gives developers the freedom to experiment with new ideas and implement innovative features.
|
||||
|
||||
**Meaningful Recognition**: Sponsoring represents a tangible way to express appreciation for the developers' dedication and hard work.
|
||||
|
||||
**Community Recognition**: Many projects publicly acknowledge their sponsors, potentially featuring you in project documentation or websites.
|
||||
|
||||
**Open Source Growth**: Your support contributes to the broader open source ecosystem, helping valuable projects thrive and grow.
|
||||
|
||||
---
|
||||
|
||||
## Post-sponsorship experience
|
||||
|
||||
After becoming a sponsor, you'll gain access to additional benefits and recognition within the Palmr community.
|
||||
|
||||
### What to expect
|
||||
|
||||
Once your sponsorship is confirmed:
|
||||
|
||||
1. **Email Confirmation**: You'll receive a confirmation email from GitHub detailing your sponsorship
|
||||
2. **Sponsor Recognition**: Your name will be added to our sponsors list and acknowledgments
|
||||
3. **Exclusive Content**: Access to sponsor-only updates, insights, and project information
|
||||
4. **Community Access**: Invitation to join our private Discord channel for sponsors
|
||||
5. **Early Access**: Priority access to new features and beta releases when available
|
||||
|
||||
### Ongoing benefits
|
||||
|
||||
As a sponsor, you become part of an exclusive community that:
|
||||
|
||||
- Receives regular updates on project development
|
||||
- Has opportunities to provide input on project direction
|
||||
- Gets recognition for supporting open source development
|
||||
- Enjoys priority support when available
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
Congratulations! You've successfully sponsored the **Palmr** project on GitHub. Your support plays a crucial role in ensuring this open source project continues to evolve and serve the community effectively.
|
||||
|
||||
### Welcome to the community
|
||||
|
||||
Your sponsorship means more than financial support—it represents a vote of confidence in the project's vision and future. We appreciate your contribution and welcome you to our growing community of supporters.
|
||||
|
||||
### Staying connected
|
||||
|
||||
Consider following the project's progress through:
|
||||
|
||||
- Regular updates in sponsor communications
|
||||
- Participation in community discussions
|
||||
- Engagement with new features and releases
|
||||
- Sharing your experience with others who might benefit from Palmr
|
||||
|
||||
Thank you for supporting open source development and helping make Palmr better for everyone.
|
144
apps/docs/content/docs/3.0-beta/gh-star.mdx
Normal file
@@ -0,0 +1,144 @@
|
||||
---
|
||||
title: Star on GitHub
|
||||
icon: Star
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Starring a project on GitHub is a simple yet powerful way to show appreciation for a repository and bookmark it for future reference. This guide walks you through starring the **Palmr** project on GitHub.
|
||||
|
||||
When you star our repository, you help increase its visibility and support the ongoing development of the project. It's a quick action that makes a meaningful difference to the project's growth.
|
||||
|
||||
---
|
||||
|
||||
## GitHub account setup
|
||||
|
||||
Before you can star a project, you'll need to be logged into your GitHub account. If you don't have an account yet, creating one is free and straightforward.
|
||||
|
||||
### Creating a New Account
|
||||
|
||||
1. Visit [GitHub's signup page](https://github.com/signup)
|
||||
2. Enter your email address
|
||||
3. Create a strong password
|
||||
4. Choose a unique username
|
||||
5. Complete the verification process
|
||||
6. Select your preferences and finish the setup
|
||||
|
||||
**Important**: Make sure to verify your email address after creating your account to access all GitHub features.
|
||||
|
||||
---
|
||||
|
||||
## Accessing the repository
|
||||
|
||||
There are several ways to find and access the Palmr repository on GitHub:
|
||||
|
||||
### Direct Access
|
||||
|
||||
The quickest method is to visit the repository directly: [https://github.com/kyantech/Palmr](https://github.com/kyantech/Palmr)
|
||||
|
||||
### Using GitHub Search
|
||||
|
||||
1. Navigate to GitHub's main page
|
||||
2. Click the search bar at the top of the page
|
||||
3. Type "Palmr" in the search field
|
||||
4. Look for the repository owned by **Kyantech**
|
||||
5. Click on the repository name to access it
|
||||
|
||||
### Through the Organization Profile
|
||||
|
||||
1. Visit Kyantech's GitHub profile
|
||||
2. Navigate to the "Repositories" tab
|
||||
3. Find and click on "Palmr"
|
||||
|
||||
---
|
||||
|
||||
## Locating the star button
|
||||
|
||||
Once you're on the Palmr repository page, you'll find the star functionality in the repository's action bar.
|
||||
|
||||
### Finding the Button
|
||||
|
||||
1. Look at the top section of the repository page
|
||||
2. Find the row of action buttons (Watch, Fork, Star)
|
||||
3. The Star button is prominently displayed with a star icon
|
||||
4. You'll see the current star count displayed next to the button
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Starring the repository
|
||||
|
||||
Clicking the star button is straightforward, and you'll receive immediate visual confirmation of your action.
|
||||
|
||||
### What happens when you star
|
||||
|
||||
After clicking the "Star" button, you'll notice several changes:
|
||||
|
||||
1. The button text changes from "Star" to "Unstar"
|
||||
2. The star count increases by one
|
||||
3. The button becomes highlighted to indicate it's active
|
||||
4. The repository is automatically added to your starred repositories list
|
||||
|
||||
### Accessing your starred repositories
|
||||
|
||||
You can view all your starred repositories anytime by:
|
||||
|
||||
- Clicking your profile picture in the top-right corner
|
||||
- Selecting "Your stars" from the dropdown menu
|
||||
- Or visiting directly: `https://github.com/[your-username]?tab=stars`
|
||||
|
||||
**Note**: To remove your star later, simply click the "Unstar" button at any time.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Why your star matters
|
||||
|
||||
Starring a repository goes beyond simple bookmarking—it's a meaningful way to support the project and its development team.
|
||||
|
||||
### Impact on the Project
|
||||
|
||||
**Shows Appreciation**: Starring demonstrates your appreciation for the hard work and effort invested in maintaining and developing the project.
|
||||
|
||||
**Increases Visibility**: Repositories with more stars gain higher visibility on GitHub, appearing more prominently in search results and recommendations.
|
||||
|
||||
**Motivates Developers**: Seeing stars encourages the development team to continue improving and expanding the project.
|
||||
|
||||
**Improves Discoverability**: GitHub's algorithm prioritizes repositories with higher star counts in trending sections and discovery features.
|
||||
|
||||
**Personal Benefits**: Starred repositories are saved to your personal list for easy access whenever you need them.
|
||||
|
||||
**Supports Open Source**: Your participation helps sustain the open-source ecosystem and the continued development of Palmr.
|
||||
|
||||
---
|
||||
|
||||
## The bigger picture
|
||||
|
||||
While starring takes only a moment, its impact on project growth and development is significant. Here's what your star represents:
|
||||
|
||||
- **Project Momentum**: Each star contributes to building momentum and community interest
|
||||
- **Community Growth**: Stars encourage more developers to discover and participate in the project
|
||||
- **Valuable Feedback**: Star counts provide insight into the project's value and community reception
|
||||
- **Development Goals**: Higher star counts help the team set ambitious goals and secure resources
|
||||
- **Sustainable Development**: Community support through stars helps maintain long-term project sustainability
|
||||
|
||||
Your star represents more than a number—it's a vote of confidence in our vision and directly influences Palmr's future development.
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
Congratulations! You've successfully starred the **Palmr** project on GitHub. Thank you for joining our community and supporting the project's growth.
|
||||
|
||||
### Additional Ways to Contribute
|
||||
|
||||
Consider exploring other ways to engage with the Palmr community:
|
||||
|
||||
- **Share the Project**: Tell others about Palmr and help expand our community
|
||||
- **Report Issues**: Help improve the project by reporting bugs or suggesting enhancements
|
||||
- **Contribute Code**: Submit pull requests to directly contribute to development
|
||||
- **Join Discussions**: Participate in community discussions and provide feedback
|
||||
|
||||
Every form of engagement helps make Palmr better for everyone in the community.
|
142
apps/docs/content/docs/3.0-beta/github-architecture.mdx
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
title: GitHub Architecture
|
||||
icon: Github
|
||||
---
|
||||
|
||||
import { File, Folder, Files } from "fumadocs-ui/components/files";
|
||||
|
||||
This guide provides a comprehensive overview of Palmr.'s GitHub repository structure, explaining how the different components are organized in the codebase. Understanding this architecture will help you navigate the repository, contribute effectively, and understand how the project is structured.
|
||||
|
||||
> **Overview:** Palmr. uses a monorepo architecture with clear separation between frontend, backend, and documentation components.
|
||||
|
||||
## Project structure
|
||||
|
||||
<Files>
|
||||
<Folder name="apps" defaultOpen>
|
||||
<Folder name="docs">
|
||||
<File name="all documentation files" />
|
||||
</Folder>
|
||||
<Folder name="server">
|
||||
<File name="all backend files" />
|
||||
</Folder>
|
||||
<Folder name="web">
|
||||
<File name="all frontend files" />
|
||||
</Folder>
|
||||
</Folder>
|
||||
<File name="other project files" />
|
||||
</Files>
|
||||
|
||||
## Core components
|
||||
|
||||
### Frontend application (apps/web)
|
||||
|
||||
**Technology stack:**
|
||||
|
||||
- Next.js 15 (App Router)
|
||||
- React 18
|
||||
- TypeScript
|
||||
- TailwindCSS
|
||||
- shadcn/ui components
|
||||
- next-intl for internationalization
|
||||
|
||||
Palmr.'s frontend is built with **Next.js 15**, using the App Router and Server Components for performance, scalability, and flexibility. The structure is modular and feature-based, keeping things easy to evolve as the product grows. UI logic runs on **React 18**, and **TypeScript** adds type safety that prevents a lot of silent bugs. Styles are handled with **TailwindCSS**, letting us build clean, responsive interfaces quickly. For components, we rely on **shadcn/ui**, a headless component library built with Radix UI and Tailwind, it's fast, accessible, and fully customizable.
|
||||
|
||||
Internationalization is handled by **next-intl**, which integrates perfectly with Next.js routing. It supports locale-aware routes, per-page translation loading, and plural rules, all without any extra client-side bloat. It's flexible, lightweight, and great for apps with multilingual audiences.
|
||||
|
||||
The frontend is organized with:
|
||||
|
||||
- A **components-based architecture** for modular UI
|
||||
- **Custom hooks** to isolate logic and side effects
|
||||
- A **route protection system** using session cookies and middleware
|
||||
- A **file management interface** integrated with the backend
|
||||
- A **reusable modal system** used for file actions, confirmations, and more
|
||||
- **Dynamic, locale-aware routing** using next-intl
|
||||
|
||||
### Backend service (apps/server)
|
||||
|
||||
**Technology stack:**
|
||||
|
||||
- Fastify
|
||||
- SQLite
|
||||
- Filesystem storage (with S3-compatible object storage support)
|
||||
- Prisma ORM
|
||||
|
||||
The backend is built on **Fastify**, a blazing-fast web framework for Node.js. It's lightweight, modular, and optimized for high performance. Every route is validated using JSON schema, which helps keep the API consistent and secure. Auth flows are built using JWTs stored in HTTP-only cookies, and everything from file uploads to token-based sharing goes through this layer.
|
||||
|
||||
Data is stored in **SQLite**, which handles user info, file metadata, session tokens, and more. For file storage, the system uses **filesystem storage** by default, keeping files organized in the local file system. The architecture also supports **S3-compatible object storage** as an alternative storage option for scalability. We use **Prisma** as our ORM to simplify database access, it gives us type-safe queries and easy-to-read code.
|
||||
|
||||
Key features include:
|
||||
|
||||
- **Authentication/authorization** with JWT + cookie sessions
|
||||
- **File management logic** including uploads, deletes, and renames
|
||||
- **Storage operations** to handle file organization, usage tracking, and cleanup
|
||||
- A **share system** that generates tokenized public file links
|
||||
- Schema-based request validation for all endpoints
|
||||
- Prisma models that keep the database logic predictable and type-safe
|
||||
|
||||
### Documentation (apps/docs)
|
||||
|
||||
**Technology stack:**
|
||||
|
||||
- Fumadocs
|
||||
- MDX (Markdown + JSX)
|
||||
- React-based components
|
||||
|
||||
The docs are built using **Fumadocs**, a modern documentation system built on top of Next.js. It uses **MDX**, so you can mix Markdown with interactive React components, perfect for developer tools and open-source projects. Pages are fast, versionable, and easy to customize. The goal is to keep the documentation as close to the codebase as possible, using shared components where needed and reusing UI patterns directly from the app.
|
||||
|
||||
It supports sidebar navigation, keyboard shortcuts, dark mode, and even interactive demos or UI previews. The file tree you see above, for example, is powered by a real React component from the docs.
|
||||
|
||||
- Built with **Fumadocs**, powered by Next.js
|
||||
- Supports **MDX** and full React component embedding
|
||||
- Ideal for technical docs and live code samples
|
||||
- Styled using the same Tailwind setup from the main app
|
||||
|
||||
### Infrastructure
|
||||
|
||||
Palmr. is fully containerized using **Docker**, which means every service: frontend, backend, database, storage, runs in its own isolated environment. With `docker-compose`, the whole stack spins up locally with a single command. It's also easy to deploy to services like Fly.io, Render, or your own VPS.
|
||||
|
||||
Volumes are used to persist data locally, and containers are networked together so that all services can talk to each other securely.
|
||||
|
||||
- **Docker-first architecture** with all services containerized
|
||||
- Configurable through `.env` and compose overrides
|
||||
- Local volumes and named networks
|
||||
- Easy to deploy and scale on any container-compatible infra
|
||||
|
||||
## Key features
|
||||
|
||||
### File management
|
||||
|
||||
Files are at the heart of Palmr. Users can upload files via the frontend, and they're stored directly in the filesystem. The backend handles metadata (name, size, type, ownership), and also handles deletion, renaming, and public sharing. Every file operation is tracked, and all actions can be scoped per user.
|
||||
|
||||
- Upload/download with instant feedback
|
||||
- File previews, type validation, and size limits
|
||||
- Token-based sharing system
|
||||
- Disk usage tracking by user
|
||||
|
||||
### User system
|
||||
|
||||
Authentication is done through secure JWTs, stored in HTTP-only cookies for safety. Signup and login flows are simple and fast, and user info is kept in sync across the frontend and backend.
|
||||
|
||||
- Cookie-based session management
|
||||
- Role support and future admin access
|
||||
- Profile updates and password reset flows
|
||||
- Logged-in user state handled via custom hooks
|
||||
|
||||
### Storage system
|
||||
|
||||
The system uses **filesystem storage** for all file operations by default. It's simple, fast, and reliable for most use cases. The architecture also supports **S3-compatible object storage** as an alternative for users who need cloud storage or additional scalability. The backend tracks usage, handles cleanup of orphaned files, and ensures that every file on disk has a matching database record.
|
||||
|
||||
- Filesystem-based storage with organized directory structure
|
||||
- Optional S3-compatible object storage support
|
||||
- Upload validation and automatic cleanup
|
||||
- Usage tracking and quotas (per user or global)
|
||||
- Secure access to stored files with proper permissions
|
||||
|
||||
### Internationalization
|
||||
|
||||
Palmr. supports multiple languages using **next-intl**, which is deeply integrated into the routing system. It loads only the necessary translations per route, supports nested namespaces, and makes it easy to keep things organized even at scale.
|
||||
|
||||
- Per-locale localstorage (`en-US`, `pt-BR`, etc.)
|
||||
- Translation loading by namespace/page
|
||||
- Full pluralization and formatting support
|
||||
- Easy translation management via JSON files
|
50
apps/docs/content/docs/3.0-beta/index.mdx
Normal file
@@ -0,0 +1,50 @@
|
||||
---
|
||||
title: Welcome to Palmr.
|
||||
icon: TreePalm
|
||||
---
|
||||
|
||||
import { Ban, Star, Shield, Palette, Users, Zap } from "lucide-react";
|
||||
|
||||

|
||||
|
||||
**Palmr.** is your go-to **open-source alternative** for file sharing, standing tall against services like **WeTransfer**, **SendGB**, **Send Anywhere**, and **Files.fm**. What sets Palmr. apart? You get to **host it on your own infrastructure** be it a **dedicated server** or **VPS** putting you in the driver’s seat for data security and file control. No more third-party dependencies or worrying about pesky limits and steep fees!
|
||||
|
||||
## Why Palmr. Rocks?
|
||||
|
||||
### No limits, seriously
|
||||
|
||||
Forget about arbitrary caps on file sizes or numbers. With Palmr., the only limit is your **server’s storage space**. Got the capacity? Then transfer files of any size or quantity without a hitch. No premium plans to unlock, no annoying ads to dodge, and definitely no hidden fees sneaking up on you. Your file sharing freedom is tied to your infrastructure, not artificial restrictions.
|
||||
|
||||
### Open source & totally free
|
||||
|
||||
Palmr. is 100% **open source** and free no licenses, subscriptions, or surprise costs. This transparency means you’ve got full control over how you use it. Here’s what that looks like:
|
||||
|
||||
- Deploy anywhere **VPS**, **dedicated server**, **Docker**, or any cloud platform you fancy.
|
||||
- Peek under the hood by reviewing the **codebase** to ensure it’s secure and meets your standards.
|
||||
- Pitch in with **improvements** or custom features to make Palmr. even better.
|
||||
- Tweak it for any use case, from personal sharing to business needs or niche applications.
|
||||
|
||||
### Your data, your rules
|
||||
|
||||
Host Palmr. on your own setup and keep **full control over your data**. By managing storage and transfers yourself, you cut out third-party risks. Your files stay in your environment no external services touching or storing them ensuring top-notch **privacy** and **confidentiality**. Set up security measures that fit your needs, and rest easy knowing no one else is in the loop. Palmr. hands you the reins for ultimate peace of mind, perfect for organizations needing strict data control or regulatory compliance.
|
||||
|
||||
### Make it yours
|
||||
|
||||
Palmr. is a canvas for customization, letting you shape every detail to match your **brand** and **user experience**:
|
||||
|
||||
- Slap on your **logo** for consistent branding across the platform.
|
||||
- Pick a **custom app name** that screams your identity.
|
||||
- Hook up an **SMTP server** for seamless email notifications about transfers or updates.
|
||||
- Rewrite **interface text** to vibe with your audience and keep your brand’s voice.
|
||||
|
||||
### Manage users like a pro
|
||||
|
||||
Take charge of your file-sharing world with Palmr.’s robust **user and admin management** system:
|
||||
|
||||
- Set up multiple **admins** to share the load and keep things running smoothly.
|
||||
- Add as many **users** as you need, from small crews to huge teams.
|
||||
- Keep tabs on **storage usage** with handy analytics for smarter resource planning.
|
||||
|
||||
### Lightning fast & feather light
|
||||
|
||||
Palmr. is built for speed with a sleek, scalable design that handles big file transfers and busy user loads without breaking a sweat. It keeps transfer speeds high and adapts to growing demands effortlessly. Thanks to smart resource use and polished code, you get a snappy experience that scales with your needs while staying rock-solid and stable.
|
251
apps/docs/content/docs/3.0-beta/manual-installation.mdx
Normal file
@@ -0,0 +1,251 @@
|
||||
---
|
||||
title: Manual Installation
|
||||
icon: Cog
|
||||
---
|
||||
|
||||
Hey there! Looking to run **Palmr.** your way, with complete control over every piece of the stack? This manual installation guide is for you. No Docker, no pre-built containers just the raw source code to tweak, customize, and deploy as you see fit.
|
||||
|
||||
> **Prefer a quicker setup?** If this hands-on approach feels like overkill, check out our [**Quick Start (Docker)**](/docs/3.0-beta/quick-start) guide for a fast, containerized deployment. This manual path is tailored for developers who want to dive deep, modify the codebase, or integrate custom services.
|
||||
|
||||
Here's what you'll do at a glance:
|
||||
|
||||
1. **Clone** the repository to get the code.
|
||||
2. **Configure** `.env` files for backend and frontend.
|
||||
3. **Install** JavaScript dependencies using `pnpm`.
|
||||
4. **Generate** the Prisma client and run database migrations.
|
||||
5. **Seed** the database with initial Palmr. data.
|
||||
6. **Build & start** the backend (Fastify API).
|
||||
7. **Build & serve** the frontend (Next.js app).
|
||||
|
||||
We've broken down each step below feel free to jump to the section you're working on!
|
||||
|
||||
## Before you start
|
||||
|
||||
Let's make sure your environment is ready to roll. Check that you've got these tools installed and set up on your system:
|
||||
|
||||
- <span style={{ color: "#16a34a" }}>Node.js</span> *(Powers our JavaScript/TypeScript
|
||||
apps)*
|
||||
- <span style={{ color: "#16a34a" }}>pnpm</span> *(Our go-to package manager)*
|
||||
- <span style={{ color: "#16a34a" }}>Git</span> *(For cloning and managing the repo)*
|
||||
|
||||
⚠️ **Heads Up on Package Managers**: Palmr. was built and tested with `pnpm`. While you _could_ try `npm`, `yarn`, or `bun`, we strongly recommend sticking with `pnpm` to avoid compatibility headaches.
|
||||
|
||||
---
|
||||
|
||||
### System requirements
|
||||
|
||||
- **Operating System**: MacOS or Linux (recommended for best results)
|
||||
- Windows works but hasn't been thoroughly tested.
|
||||
- **Memory**: At least 4GB RAM is suggested.
|
||||
- **Storage**: Depends on how much file storage you'll need.
|
||||
- **CPU**: 2+ cores for smooth performance.
|
||||
|
||||
---
|
||||
|
||||
## Let's Get Palmr. Running
|
||||
|
||||
### Step 1: Clone the repository
|
||||
|
||||
First things first, grab a local copy of the Palmr. codebase. Run this command to clone the official repo:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/kyantech/Palmr.git
|
||||
```
|
||||
|
||||
Once it's done, you'll have a new directory with the project structure. Inside, the `apps` folder holds the key pieces: `docs`, `server`, and `web`. For this guide, we're focusing on `server` (our Fastify backend) and `web` (our Next.js frontend).
|
||||
|
||||
---
|
||||
|
||||
### Step 2: Set up the backend
|
||||
|
||||
Let's get the backend up and running. Start by navigating to the server directory:
|
||||
|
||||
```bash
|
||||
cd ./apps/server
|
||||
```
|
||||
|
||||
#### Configure environment variables
|
||||
|
||||
Before anything else, we need to set up the environment variables Palmr. relies on. We've included a handy template file called `.env.example` to get you started. Create your own `.env` file with this command:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
This copies the template into a new `.env` file with all the necessary settings. Open it up if you need to tweak anything specific to your setup.
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
Next, let's install the backend dependencies. With Node.js and `pnpm` ready, run:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
This pulls in everything needed for the backend, including Prisma, our database ORM.
|
||||
|
||||
#### Generate Prisma client
|
||||
|
||||
Now, generate the Prisma client tailored for Palmr. with:
|
||||
|
||||
```bash
|
||||
pnpm dlx prisma generate
|
||||
```
|
||||
|
||||
This sets up the interface for smooth database interactions.
|
||||
|
||||
#### Deploy Prisma migrations
|
||||
|
||||
With the client ready, apply the database schema using:
|
||||
|
||||
```bash
|
||||
pnpm dlx prisma migrate deploy
|
||||
```
|
||||
|
||||
This ensures your database structure is set up with all the required migrations.
|
||||
|
||||
#### Seed the database
|
||||
|
||||
Let's populate the database with some initial data. Run the seeding script:
|
||||
|
||||
```bash
|
||||
pnpm db:seed
|
||||
```
|
||||
|
||||
This adds the baseline data Palmr. needs to function properly.
|
||||
|
||||
#### Build and run the backend
|
||||
|
||||
Finally, build the backend app:
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Once the build is complete, start the service:
|
||||
|
||||
```bash
|
||||
pnpm start
|
||||
```
|
||||
|
||||
To confirm everything's working, check out the API documentation at:
|
||||
|
||||
```bash
|
||||
http://localhost:3333/docs
|
||||
```
|
||||
|
||||
This page lists all available API endpoints and how to use them.
|
||||
|
||||
---
|
||||
|
||||
### Step 3: Set up the frontend
|
||||
|
||||
With the backend humming, let's tackle the frontend setup.
|
||||
|
||||
#### Navigate to the Frontend Directory
|
||||
|
||||
If you're in the `server` folder, move to `web` with:
|
||||
|
||||
```bash
|
||||
cd ../web
|
||||
```
|
||||
|
||||
Or, from the repo root, use:
|
||||
|
||||
```bash
|
||||
cd apps/web
|
||||
```
|
||||
|
||||
#### Configure environment variables
|
||||
|
||||
Just like the backend, set up the frontend environment variables:
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
This creates a `.env` file with the necessary configurations for the frontend.
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
Install all the frontend dependencies:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
#### Build and run the frontend
|
||||
|
||||
Build the production version of the frontend:
|
||||
|
||||
```bash
|
||||
pnpm run build
|
||||
```
|
||||
|
||||
Once that's done, serve it up:
|
||||
|
||||
```bash
|
||||
pnpm serve
|
||||
```
|
||||
|
||||
Now, open your browser and head to:
|
||||
|
||||
```bash
|
||||
http://localhost:3000
|
||||
```
|
||||
|
||||
You should see the full Palmr. application ready to go!
|
||||
|
||||
---
|
||||
|
||||
## Quick notes
|
||||
|
||||
This guide sets up Palmr. using the local file system for storage. Want to use an S3-compatible object storage instead? You can configure that in the `.env` file. Check the Palmr. documentation for details on setting up S3 storage just update the environment variables, then build and run as shown here.
|
||||
|
||||
---
|
||||
|
||||
## Command cheat sheet
|
||||
|
||||
Here's a quick reference for all the commands we've covered perfect for copy-pasting once you're familiar with the steps:
|
||||
|
||||
```bash
|
||||
# --- Backend (Fastify API) ---
|
||||
cd apps/server
|
||||
pnpm install
|
||||
pnpm dlx prisma generate
|
||||
pnpm dlx prisma migrate deploy
|
||||
pnpm db:seed
|
||||
pnpm run build
|
||||
pnpm start
|
||||
|
||||
# --- Frontend (Next.js) ---
|
||||
cd apps/web
|
||||
pnpm install
|
||||
pnpm run build
|
||||
pnpm serve
|
||||
```
|
||||
|
||||
> **Tip**: Keep this handy in your clipboard for your first setup run.
|
||||
|
||||
---
|
||||
|
||||
## What's next?
|
||||
|
||||
Palmr. is now up and running locally . Here are some suggested next steps:
|
||||
|
||||
- **Manage Users**: Dive into the [Users Management](/docs/3.0-beta/manage-users) guide.
|
||||
- **Switch to Object Storage**: Update `.env` variables to use an S3-compatible bucket (see Quick Notes above).
|
||||
- **Secure Your Instance**: Put Palmr. behind a reverse proxy like **Nginx** or **Caddy** and enable HTTPS.
|
||||
- **Learn the Internals**: Explore how everything connects in the [Architecture](/docs/3.0-beta/architecture) overview.
|
||||
|
||||
Jump into whichever area fits your needs our docs are designed for exploration in any order.
|
||||
|
||||
## Wrapping up
|
||||
|
||||
Congrats! You've successfully set up a production-ready instance of Palmr. through this detailed manual process. From cloning the repo to deploying the app, you've tackled every step like a pro.
|
||||
|
||||
## Helpful resources
|
||||
|
||||
- [Node.js Documentation](https://nodejs.org/en/docs/)
|
||||
- [pnpm Documentation](https://pnpm.io/)
|
||||
- [Prisma Documentation](https://www.prisma.io/docs/)
|
32
apps/docs/content/docs/3.0-beta/meta.json
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"title": "v3.0-beta",
|
||||
"description": "Latest version",
|
||||
"root": true,
|
||||
"icon": "Sparkles",
|
||||
"pages": [
|
||||
"---Introduction---",
|
||||
"index",
|
||||
"quick-start",
|
||||
"installation",
|
||||
"manual-installation",
|
||||
"screenshots",
|
||||
"s3-providers",
|
||||
"---Configuration---",
|
||||
"configuring-smtp",
|
||||
"available-languages",
|
||||
"uid-gid-configuration",
|
||||
"reverse-proxy-configuration",
|
||||
"password-reset-without-smtp",
|
||||
"oidc-authentication",
|
||||
"---Developers---",
|
||||
"architecture",
|
||||
"github-architecture",
|
||||
"api",
|
||||
"translation-management",
|
||||
"contribute",
|
||||
"open-an-issue",
|
||||
"---Sponsor this project---",
|
||||
"gh-star",
|
||||
"gh-sponsor"
|
||||
]
|
||||
}
|
315
apps/docs/content/docs/3.0-beta/oidc-authentication.mdx
Normal file
@@ -0,0 +1,315 @@
|
||||
---
|
||||
title: OIDC Authentication
|
||||
icon: Key
|
||||
---
|
||||
|
||||
Palmr supports OpenID Connect (OIDC) authentication, allowing users to sign in using external identity providers such as Google, Microsoft Azure AD, Keycloak, Auth0, and other OIDC-compliant services. This feature provides seamless single sign-on (SSO) capabilities and centralized user management.
|
||||
|
||||
OIDC authentication in Palmr is built using the industry-standard OpenID Connect protocol with PKCE (Proof Key for Code Exchange) for enhanced security. The implementation supports automatic user provisioning, role mapping, and flexible configuration options.
|
||||
|
||||
## Why use OIDC authentication?
|
||||
|
||||
OIDC authentication provides several advantages for organizations and users:
|
||||
|
||||
**Centralized Authentication**: Users can authenticate using their existing organizational credentials without creating separate accounts for Palmr.
|
||||
|
||||
**Enhanced Security**: OIDC provides robust security features including token-based authentication, PKCE flow, and standardized protocols.
|
||||
|
||||
**Single Sign-On**: Users can access Palmr seamlessly if they're already authenticated with their identity provider.
|
||||
|
||||
**User Management**: Administrators can manage user access centrally through their existing identity provider.
|
||||
|
||||
**Compliance**: OIDC helps meet organizational security and compliance requirements by leveraging existing identity infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before configuring OIDC authentication, ensure you have:
|
||||
|
||||
- **Administrative Access**: ADMIN privileges in Palmr to configure OIDC settings
|
||||
- **Identity Provider**: An OIDC-compliant identity provider (Google, Azure AD, Keycloak, etc.)
|
||||
- **Application Registration**: Your Palmr application registered with your identity provider
|
||||
- **OIDC Credentials**: Client ID, Client Secret, and Issuer URL from your identity provider
|
||||
|
||||
### Supported identity providers
|
||||
|
||||
Palmr's OIDC implementation is compatible with any OpenID Connect 1.0 compliant provider, including:
|
||||
|
||||
- **Google Workspace / Google Cloud Identity**
|
||||
- **Microsoft Azure Active Directory / Entra ID**
|
||||
- **Keycloak**
|
||||
- **Auth0**
|
||||
- **Okta**
|
||||
- **AWS Cognito**
|
||||
- **Custom OIDC providers**
|
||||
|
||||
---
|
||||
|
||||
## Configuring OIDC settings
|
||||
|
||||
OIDC configuration is managed through Palmr's administrative settings panel, accessible only to users with ADMIN privileges.
|
||||
|
||||
### Accessing OIDC configuration
|
||||
|
||||
To configure OIDC authentication:
|
||||
|
||||
1. **Access Settings**: Click on your profile picture in the header and select **Settings**
|
||||
2. **Navigate to Authentication**: Find the **Authentication** or **OIDC** configuration section
|
||||
3. **Enable OIDC**: Toggle the OIDC authentication option to enable it
|
||||
|
||||

|
||||
|
||||
### Required configuration fields
|
||||
|
||||
Configure the following essential fields for OIDC authentication:
|
||||
|
||||
**OIDC Enabled**: Enable or disable OIDC authentication for your Palmr instance.
|
||||
|
||||
**Issuer URL**: The base URL of your OIDC identity provider. This is typically the discovery endpoint URL without the `/.well-known/openid-configuration` suffix.
|
||||
|
||||
- Example: `https://accounts.google.com`
|
||||
- Example: `https://login.microsoftonline.com/{tenant-id}/v2.0`
|
||||
|
||||
**Client ID**: The unique identifier for your Palmr application as registered with your identity provider.
|
||||
|
||||
**Client Secret**: The secret key provided by your identity provider for your Palmr application. Store this securely and never share it.
|
||||
|
||||
**Redirect URI**: The callback URL where users will be redirected after authentication. This is typically auto-detected but can be manually configured if needed.
|
||||
|
||||
- Format: `https://your-palmr-domain.com/api/auth/oidc/callback`
|
||||
|
||||
**Scope**: The OpenID Connect scopes to request from the identity provider. Default is `openid profile email`.
|
||||
|
||||

|
||||
|
||||
### Advanced configuration options
|
||||
|
||||
**Auto-Registration**: Configure whether new users can be automatically created when they authenticate via OIDC for the first time.
|
||||
|
||||
**Admin Email Domains**: Specify email domains that should automatically receive admin privileges when registering via OIDC.
|
||||
|
||||
**User Attribute Mapping**: Configure how user attributes from the OIDC provider map to Palmr user fields.
|
||||
|
||||
---
|
||||
|
||||
## Setting up identity providers
|
||||
|
||||
The setup process varies depending on your chosen identity provider. Here are examples for common providers:
|
||||
|
||||
### Google Workspace / Google Cloud
|
||||
|
||||
1. **Create Project**: Go to the [Google Cloud Console](https://console.cloud.google.com/) and create a new project
|
||||
2. **Enable APIs**: Enable the Google+ API and OpenID Connect API
|
||||
3. **Create Credentials**: Create OAuth 2.0 credentials for a web application
|
||||
4. **Configure Redirect URI**: Add your Palmr callback URL to authorized redirect URIs
|
||||
5. **Note Credentials**: Copy the Client ID and Client Secret for Palmr configuration
|
||||
|
||||
**Configuration values:**
|
||||
|
||||
- **Issuer URL**: `https://accounts.google.com`
|
||||
- **Scope**: `openid profile email`
|
||||
|
||||
### Microsoft Azure AD / Entra ID
|
||||
|
||||
1. **Register Application**: Go to Azure Portal > Azure Active Directory > App registrations
|
||||
2. **Create Registration**: Register a new application with web platform
|
||||
3. **Configure Authentication**: Add your Palmr callback URL to redirect URIs
|
||||
4. **Create Secret**: Generate a client secret in Certificates & secrets
|
||||
5. **Note Configuration**: Copy Application (client) ID and Directory (tenant) ID
|
||||
|
||||
**Configuration values:**
|
||||
|
||||
- **Issuer URL**: `https://login.microsoftonline.com/{tenant-id}/v2.0`
|
||||
- **Scope**: `openid profile email`
|
||||
|
||||
### Keycloak
|
||||
|
||||
1. **Create Client**: In your Keycloak realm, create a new OpenID Connect client
|
||||
2. **Configure Client**: Set access type to confidential and enable standard flow
|
||||
3. **Set Redirect URI**: Add your Palmr callback URL to valid redirect URIs
|
||||
4. **Generate Secret**: Note the client secret from the Credentials tab
|
||||
|
||||
**Configuration values:**
|
||||
|
||||
- **Issuer URL**: `https://your-keycloak-domain.com/realms/{realm-name}`
|
||||
- **Scope**: `openid profile email`
|
||||
|
||||

|
||||
|
||||
### Zitadel
|
||||
1. **Create New ProjectApp**: In your desired Zitadel project, create a new application
|
||||
2. **Name and Type**: Give your application a name and choose **WEB** as the application type
|
||||
3. **Authentication Method**: Choose Code
|
||||
4. **Set Redirect URI**: Add your Palmr callback URL to valid redirect URIs
|
||||
5. **Finish**: After reviewing the configuration create the application
|
||||
6. **Copy the client ID and client Secrat**: Copy the client id paste it into the **Client ID** of your Palmr OIDC condiguration Form, repeat for the client secret and paste it into the **Client Secret** field
|
||||
7. **Obtain your Provider URL**: In your Zitadel application go to **URLs** and copy the **Authorization Endpoint (remove the /authorize from that url)** e.g. https://auth.example.com/oauth/v2
|
||||
|
||||
**Configuration values:**
|
||||
|
||||
- **Issuer URL**: Depends on your Zitadel installation and project. Example: `https://auth.example.com/oauth/v2`
|
||||
- **Scope**: `openid profile email`
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Testing OIDC configuration
|
||||
|
||||
After configuring OIDC settings, it's important to test the authentication flow to ensure everything works correctly.
|
||||
|
||||
### Validation steps
|
||||
|
||||
1. **Save Configuration**: Apply your OIDC settings in the Palmr admin panel
|
||||
2. **Check Status**: Verify that OIDC is enabled and properly configured
|
||||
3. **Test Login Flow**: Attempt to log in using the OIDC provider
|
||||
4. **Verify User Creation**: Confirm that user accounts are created or updated correctly
|
||||
|
||||
### Testing the authentication flow
|
||||
|
||||
1. **Access Login Page**: Navigate to your Palmr login page
|
||||
2. **OIDC Login Option**: Look for the OIDC/SSO login button or option
|
||||
3. **Provider Redirect**: Click the OIDC login option to redirect to your identity provider
|
||||
4. **Authenticate**: Complete authentication with your identity provider
|
||||
5. **Return to Palmr**: Verify successful redirect back to Palmr with authentication
|
||||
|
||||

|
||||
|
||||
### Troubleshooting common issues
|
||||
|
||||
**Configuration Errors**:
|
||||
|
||||
- Verify that all required fields are filled correctly
|
||||
- Check that the Issuer URL is accessible and returns valid OIDC metadata
|
||||
- Ensure Client ID and Client Secret match your identity provider configuration
|
||||
|
||||
**Redirect URI Mismatches**:
|
||||
|
||||
- Confirm that the redirect URI in Palmr matches what's configured in your identity provider
|
||||
- Check for protocol mismatches (HTTP vs HTTPS)
|
||||
- Verify that the domain and path are exactly correct
|
||||
|
||||
**Authentication Failures**:
|
||||
|
||||
- Check that the user exists in your identity provider
|
||||
- Verify that required scopes are granted
|
||||
- Ensure the user has necessary permissions in the identity provider
|
||||
|
||||
**User Creation Issues**:
|
||||
|
||||
- Confirm that auto-registration is enabled if you want new users to be created automatically
|
||||
- Check that email addresses are provided by the identity provider
|
||||
- Verify admin domain configuration if users should receive admin privileges
|
||||
|
||||
---
|
||||
|
||||
## User experience
|
||||
|
||||
Once OIDC is properly configured, users will have a seamless authentication experience integrated into Palmr's login flow.
|
||||
|
||||
### Login process
|
||||
|
||||
1. **Access Palmr**: Users navigate to the Palmr login page
|
||||
2. **Choose OIDC**: Users select the OIDC/SSO login option
|
||||
3. **Provider Authentication**: Users are redirected to authenticate with their identity provider
|
||||
4. **Automatic Return**: After successful authentication, users are automatically redirected back to Palmr
|
||||
5. **Dashboard Access**: Users gain immediate access to their Palmr dashboard
|
||||
|
||||
### User account management
|
||||
|
||||
**Automatic Provisioning**: New users are automatically created when they first authenticate via OIDC (if auto-registration is enabled).
|
||||
|
||||
**Profile Synchronization**: User profile information (name, email) is synchronized from the identity provider during each login.
|
||||
|
||||
**Role Assignment**: User roles and permissions can be automatically assigned based on identity provider attributes or configured rules.
|
||||
|
||||
### Account unification
|
||||
|
||||
**Email-Based Matching**: If a user authenticates via OIDC using the same email address as an existing credential-based account, both authentication methods will be linked to the same user account.
|
||||
|
||||
**Dual Authentication Options**: Users who have both credential-based and OIDC authentication set up can choose either method to log in:
|
||||
|
||||
- Traditional email/password authentication
|
||||
- OIDC/SSO authentication through their identity provider
|
||||
|
||||
**Seamless Experience**: Regardless of which authentication method is used, users will access the same account with all their files, shares, and settings preserved.
|
||||
|
||||
**Account Consolidation**: This feature ensures that users don't accidentally create duplicate accounts and can transition smoothly between authentication methods as organizational requirements change.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Security considerations
|
||||
|
||||
OIDC authentication in Palmr implements several security best practices to ensure safe and secure authentication.
|
||||
|
||||
### Security features
|
||||
|
||||
**PKCE Flow**: Palmr uses Proof Key for Code Exchange (PKCE) to prevent authorization code interception attacks.
|
||||
|
||||
**State Parameter**: Random state parameters are used to prevent CSRF attacks during the authentication flow.
|
||||
|
||||
**Token Validation**: All tokens are properly validated according to OIDC specifications.
|
||||
|
||||
**Secure Storage**: Sensitive configuration data is securely stored and never exposed to client-side code.
|
||||
|
||||
### Best practices
|
||||
|
||||
**Use HTTPS**: Always configure Palmr and your identity provider to use HTTPS in production environments.
|
||||
|
||||
**Rotate Secrets**: Regularly rotate client secrets and update them in both your identity provider and Palmr configuration.
|
||||
|
||||
**Monitor Access**: Regularly review user access and authentication logs to detect any suspicious activity.
|
||||
|
||||
**Limit Scopes**: Only request the minimum necessary scopes from your identity provider.
|
||||
|
||||
**Validate Domains**: Configure admin email domains carefully to prevent unauthorized privilege escalation.
|
||||
|
||||
---
|
||||
|
||||
## API endpoints
|
||||
|
||||
Palmr provides several API endpoints for OIDC authentication that can be used for integration or troubleshooting.
|
||||
|
||||
### Available endpoints
|
||||
|
||||
**GET /api/auth/oidc/config**: Retrieve OIDC configuration and status information.
|
||||
|
||||
**GET /api/auth/oidc/authorize**: Initiate the OIDC authorization flow.
|
||||
|
||||
**GET /api/auth/oidc/callback**: Handle the callback from the identity provider after authentication.
|
||||
|
||||
## Finalizing OIDC configuration
|
||||
|
||||
After completing the configuration and testing process, your Palmr installation will be ready to handle OIDC authentication seamlessly.
|
||||
|
||||
### Configuration completion
|
||||
|
||||
Once OIDC is properly configured:
|
||||
|
||||
1. **Verify Settings**: Confirm all configuration fields are correct and saved
|
||||
2. **Test Authentication**: Perform end-to-end testing of the authentication flow
|
||||
3. **Document Configuration**: Keep a record of your OIDC settings for future reference
|
||||
4. **Inform Users**: Notify users about the new OIDC authentication option
|
||||
|
||||
### Ongoing maintenance
|
||||
|
||||
To maintain reliable OIDC authentication:
|
||||
|
||||
- **Monitor Authentication**: Regularly check that OIDC authentication is working correctly
|
||||
- **Update Credentials**: Rotate client secrets periodically for security
|
||||
- **Review User Access**: Audit user accounts and permissions regularly
|
||||
- **Stay Updated**: Keep informed about changes to your identity provider's configuration
|
||||
|
||||
### Next steps
|
||||
|
||||
With OIDC properly configured, your Palmr installation now provides:
|
||||
|
||||
- Seamless single sign-on authentication for users
|
||||
- Centralized user management through your identity provider
|
||||
- Enhanced security through industry-standard protocols
|
||||
- Improved user experience with reduced password management
|
||||
|
||||
Users can now authenticate using their existing organizational credentials, providing a more streamlined and secure access experience to Palmr's file sharing capabilities.
|
333
apps/docs/content/docs/3.0-beta/open-an-issue.mdx
Normal file
@@ -0,0 +1,333 @@
|
||||
---
|
||||
title: How to Open an Issue
|
||||
icon: Ticket
|
||||
---
|
||||
|
||||
## Introduction
|
||||
|
||||
Opening an issue on GitHub is an essential way to report bugs, request features, or ask questions about a project. This guide walks you through the process of creating an issue for the **Palmr** project on GitHub.
|
||||
|
||||
Issues serve as a vital communication tool in open source development, helping track bugs, feature requests, and general questions. They create a transparent record of project discussions and improvements, fostering collaboration between users and maintainers.
|
||||
|
||||
Whether you've discovered a bug that needs fixing, have an idea for a new feature, or need clarification about functionality, creating an issue is the first step to getting your voice heard and contributing to the project's improvement.
|
||||
|
||||
---
|
||||
|
||||
## GitHub account requirements
|
||||
|
||||
Before you can open an issue, you'll need to be logged into your GitHub account. If you don't have an account yet, creating one is free and provides access to the entire GitHub ecosystem.
|
||||
|
||||
### Account benefits
|
||||
|
||||
Having a GitHub account allows you to:
|
||||
|
||||
- Create and manage issues across all repositories
|
||||
- Comment on existing issues and participate in discussions
|
||||
- Receive notifications about updates and responses
|
||||
- Collaborate with developers and maintainers
|
||||
- Track your contributions and engagement history
|
||||
|
||||
### Getting started
|
||||
|
||||
If you need to create an account:
|
||||
|
||||
1. Visit [GitHub's signup page](https://github.com/signup)
|
||||
2. Complete the registration process
|
||||
3. Verify your email address
|
||||
4. Log in to your new account
|
||||
|
||||
Make sure you're logged in before proceeding to the next steps.
|
||||
|
||||
---
|
||||
|
||||
## Accessing the repository
|
||||
|
||||
There are several convenient ways to access the Palmr repository and begin the issue creation process.
|
||||
|
||||
### Direct access
|
||||
|
||||
The quickest method is to visit the repository directly: [https://github.com/kyantech/Palmr](https://github.com/kyantech/Palmr)
|
||||
|
||||
### Alternative access methods
|
||||
|
||||
You can also find the repository through:
|
||||
|
||||
**GitHub Search**:
|
||||
|
||||
- Click the search bar at the top of any GitHub page
|
||||
- Type "Palmr" or "kyantech/Palmr" for more specific results
|
||||
- Look for the repository owned by **Kyantech**
|
||||
- Click on the repository name to access it
|
||||
|
||||
**Organization Profile**:
|
||||
|
||||
- Visit [Kyantech's GitHub profile](https://github.com/kyantech)
|
||||
- Navigate to the "Repositories" tab
|
||||
- Find and click on "Palmr" in the repository list
|
||||
|
||||
### Repository verification
|
||||
|
||||
When accessing the repository, verify you're in the correct location by checking:
|
||||
|
||||
- The repository owner is **kyantech**
|
||||
- The repository name is **Palmr**
|
||||
- The description matches the project you're looking for
|
||||
- Recent activity indicates an active project
|
||||
|
||||
---
|
||||
|
||||
## Navigating to issues
|
||||
|
||||
Once you're on the repository page, you'll need to access the issues section to create your new issue.
|
||||
|
||||
### Finding the issues tab
|
||||
|
||||
To access the issues section:
|
||||
|
||||
1. **Locate Navigation Bar**: Look at the navigation bar near the top of the repository page
|
||||
2. **Find Issues Tab**: The **Issues** tab is typically located between "Code" and "Pull requests"
|
||||
3. **Click Issues**: Click on the **Issues** tab to open the issues section
|
||||
4. **Review Existing Issues**: You'll see a list of all existing issues, both open and closed
|
||||
|
||||
### Understanding the issues interface
|
||||
|
||||
The issues tab displays important information including:
|
||||
|
||||
- **Issue Count**: Number of open and closed issues
|
||||
- **Labels and Categories**: Color-coded labels for organization
|
||||
- **Issue Status**: Visual indicators for open/closed status
|
||||
- **Recent Activity**: Timeline of recent issue updates
|
||||
- **Assigned Contributors**: Who's working on specific issues
|
||||
- **Search and Filter Options**: Tools to find specific issues
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Creating a new issue
|
||||
|
||||
With the issues section open, you can now create your new issue to report a bug, request a feature, or ask a question.
|
||||
|
||||
### Initiating issue creation
|
||||
|
||||
To start creating your issue:
|
||||
|
||||
1. **Locate New Issue Button**: Look for the green **New Issue** button, typically on the right side of the issues page
|
||||
2. **Click to Create**: Click the button to open the issue creation interface
|
||||
3. **Select Template**: If multiple issue templates are available, choose the most appropriate one for your needs
|
||||
4. **Review Requirements**: Take time to read through any template requirements or guidelines
|
||||
|
||||
### Pre-creation checklist
|
||||
|
||||
Before creating your issue, consider these important steps:
|
||||
|
||||
- **Search Existing Issues**: Check if your issue has already been reported to avoid duplicates
|
||||
- **Review Guidelines**: Read any contribution guidelines or issue templates provided
|
||||
- **Gather Information**: Collect all necessary details, screenshots, or error messages
|
||||
- **Consider Labels**: Think about which labels might be appropriate for your issue
|
||||
- **Reference Related Items**: Note any related issues or pull requests that might be relevant
|
||||
|
||||
### Best practices for issue creation
|
||||
|
||||
- **Use Clear Language**: Write in a way that's easy for others to understand
|
||||
- **Be Specific**: Provide concrete details rather than vague descriptions
|
||||
- **Include Context**: Explain the circumstances surrounding your issue
|
||||
- **Add Visual Evidence**: Screenshots or recordings can be very helpful
|
||||
- **Format Properly**: Use markdown formatting to improve readability
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Completing the issue form
|
||||
|
||||
The issue creation form is your opportunity to provide comprehensive information about your bug report, feature request, or question.
|
||||
|
||||
### Essential form fields
|
||||
|
||||
You'll encounter several key fields that need your attention:
|
||||
|
||||
**Issue Title**:
|
||||
|
||||
- Write a clear, concise title that summarizes the issue
|
||||
- Use descriptive language that helps others understand the problem at a glance
|
||||
- Avoid vague titles like "Bug" or "Problem"
|
||||
- Include key terms that others might search for
|
||||
|
||||
**Issue Description**:
|
||||
|
||||
- Provide a detailed explanation of your issue
|
||||
- For bugs: Include steps to reproduce, expected behavior, and actual behavior
|
||||
- For features: Explain the functionality you'd like and why it would be valuable
|
||||
- For questions: Be specific about what you need clarification on
|
||||
|
||||
### Additional form options
|
||||
|
||||
**Labels (Optional)**:
|
||||
|
||||
- Add relevant labels to categorize your issue (e.g., `bug`, `enhancement`, `question`)
|
||||
- Labels help maintainers organize and prioritize issues effectively
|
||||
- Choose labels that accurately represent your issue type and priority
|
||||
|
||||
**Attachments (Optional)**:
|
||||
|
||||
- Include screenshots to illustrate visual problems or desired features
|
||||
- Attach log files or error messages for technical issues
|
||||
- Add mockups or diagrams for feature requests
|
||||
- Include any relevant documentation or examples
|
||||
|
||||
### Writing effective descriptions
|
||||
|
||||
For **Bug Reports**, include:
|
||||
|
||||
- Clear steps to reproduce the issue
|
||||
- Expected vs. actual behavior
|
||||
- System information (OS, browser, version)
|
||||
- Error messages or console output
|
||||
- Screenshots or screen recordings
|
||||
|
||||
For **Feature Requests**, include:
|
||||
|
||||
- Detailed description of the desired functionality
|
||||
- Use cases and benefits
|
||||
- Potential implementation suggestions
|
||||
- Examples from other projects (if applicable)
|
||||
|
||||
For **Questions**, include:
|
||||
|
||||
- Specific area of confusion
|
||||
- What you've already tried
|
||||
- Relevant code snippets or configurations
|
||||
- Context about your use case
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Submitting your issue
|
||||
|
||||
After carefully completing the issue form, you're ready to submit your contribution to the project.
|
||||
|
||||
### Final review
|
||||
|
||||
Before submitting, take a moment to:
|
||||
|
||||
- **Review Content**: Read through your title and description for clarity
|
||||
- **Check Formatting**: Ensure proper markdown formatting and readability
|
||||
- **Verify Attachments**: Confirm all screenshots and files are properly attached
|
||||
- **Validate Information**: Double-check that all details are accurate and complete
|
||||
|
||||
### Submission process
|
||||
|
||||
1. **Click Submit**: Click the **Create** button at the bottom of the form
|
||||
2. **Confirmation**: Your issue will be created and assigned a unique number
|
||||
3. **Visibility**: The issue becomes immediately visible to maintainers and contributors
|
||||
4. **Notifications**: You'll receive notifications for any updates or responses
|
||||
|
||||
### Post-submission expectations
|
||||
|
||||
After submitting your issue:
|
||||
|
||||
- **Track Progress**: Monitor your issue for responses and updates
|
||||
- **Stay Engaged**: Participate in any follow-up discussions
|
||||
- **Provide Clarification**: Be ready to answer questions or provide additional information
|
||||
- **Be Patient**: Remember that maintainers may need time to review and respond
|
||||
|
||||
---
|
||||
|
||||
## Issue management best practices
|
||||
|
||||
To ensure your issue receives appropriate attention and contributes effectively to the project, follow these proven practices.
|
||||
|
||||
### Communication guidelines
|
||||
|
||||
**Be Clear and Specific**: Provide comprehensive details that help others understand your issue without ambiguity.
|
||||
|
||||
**Use Descriptive Titles**: Craft titles that immediately convey the nature and scope of your issue.
|
||||
|
||||
**Include Reproduction Steps**: For bugs, provide step-by-step instructions that others can follow to reproduce the problem.
|
||||
|
||||
**Maintain Professional Tone**: Remember that maintainers and contributors are often volunteers dedicating their time to help.
|
||||
|
||||
### Technical best practices
|
||||
|
||||
**Provide System Information**: Include relevant details about your environment, versions, and configuration.
|
||||
|
||||
**Format Code Properly**: Use markdown code blocks for any code snippets, error messages, or configuration files.
|
||||
|
||||
**Update Regularly**: Keep your issue current with new information or changes in status.
|
||||
|
||||
**Reference Related Issues**: Link to related issues or pull requests when relevant.
|
||||
|
||||
### Community engagement
|
||||
|
||||
**Respond Promptly**: When maintainers ask questions or request clarification, respond in a timely manner.
|
||||
|
||||
**Help Others**: If you see similar issues, share your experience or solutions.
|
||||
|
||||
**Follow Up**: Update the issue if you find a solution or workaround independently.
|
||||
|
||||
**Express Gratitude**: Thank contributors and maintainers for their time and assistance.
|
||||
|
||||
---
|
||||
|
||||
## The importance of quality issues
|
||||
|
||||
Understanding why well-crafted issues matter helps you contribute more effectively to the open source ecosystem.
|
||||
|
||||
### Project improvement
|
||||
|
||||
**Bug Identification**: Your detailed bug reports help identify and fix problems that affect all users.
|
||||
|
||||
**Feature Development**: Thoughtful feature requests guide project development and prioritization.
|
||||
|
||||
**Documentation Enhancement**: Questions about unclear functionality often lead to improved documentation.
|
||||
|
||||
### Maintainer support
|
||||
|
||||
**Efficient Triage**: Clear, detailed issues help maintainers quickly understand and categorize problems.
|
||||
|
||||
**Reduced Back-and-forth**: Comprehensive initial reports minimize the need for follow-up questions.
|
||||
|
||||
**Priority Assessment**: Well-documented issues help maintainers assess impact and urgency.
|
||||
|
||||
### Community collaboration
|
||||
|
||||
**Knowledge Sharing**: Issues create a searchable knowledge base for future users with similar problems.
|
||||
|
||||
**Contributor Attraction**: Interesting issues often attract new contributors who want to help solve problems.
|
||||
|
||||
**Discussion Platform**: Issues provide a space for community members to collaborate on solutions.
|
||||
|
||||
---
|
||||
|
||||
## Next steps
|
||||
|
||||
Congratulations on creating your issue for the **Palmr** project! Your contribution is valuable and helps make the project better for the entire community.
|
||||
|
||||
### Staying engaged
|
||||
|
||||
After creating your issue, consider these ways to remain involved:
|
||||
|
||||
- **Monitor Progress**: Keep track of responses and updates to your issue
|
||||
- **Participate Actively**: Engage in discussions and provide additional information when requested
|
||||
- **Help Others**: Assist other community members with similar issues when possible
|
||||
- **Share Knowledge**: Document any solutions or workarounds you discover
|
||||
|
||||
### Expanding your contribution
|
||||
|
||||
Beyond issue creation, you can contribute to the project in other ways:
|
||||
|
||||
- **Code Contributions**: Consider submitting pull requests to fix bugs or implement features
|
||||
- **Documentation**: Help improve project documentation based on your experience
|
||||
- **Community Support**: Answer questions and help other users in issues and discussions
|
||||
- **Project Promotion**: Share Palmr with others who might benefit from the project
|
||||
|
||||
### Building relationships
|
||||
|
||||
- **Follow the Project**: Star the repository to show support and stay updated
|
||||
- **Connect with Contributors**: Engage respectfully with maintainers and other contributors
|
||||
- **Join Discussions**: Participate in broader project discussions and planning
|
||||
- **Spread Awareness**: Help others discover and benefit from the Palmr project
|
||||
|
||||
Thank you for being part of the open source community and contributing to making Palmr better for everyone. Your participation, whether through issues, code, or community engagement, helps drive the project forward and benefits users worldwide.
|
181
apps/docs/content/docs/3.0-beta/password-reset-without-smtp.mdx
Normal file
@@ -0,0 +1,181 @@
|
||||
---
|
||||
title: Password Reset Without SMTP
|
||||
icon: Lock
|
||||
---
|
||||
|
||||
This guide provides detailed instructions on how to reset a user password directly inside the Docker container for Palmr, without requiring SMTP configuration. This method is particularly useful for administrators who do not have email services set up or need to regain access to accounts in emergency situations.
|
||||
|
||||
## When and why to use this method
|
||||
|
||||
Resetting a password without SMTP is an alternative approach for specific scenarios where the standard email-based reset is not feasible. Consider using this method if:
|
||||
|
||||
- An admin user is locked out and cannot access their email for a password reset.
|
||||
- SMTP services are not configured or are experiencing issues.
|
||||
- You need to perform emergency system recovery and restore access quickly.
|
||||
- You are setting up an initial environment and need to configure accounts.
|
||||
- You are conducting controlled testing in a development setup.
|
||||
|
||||
> **Warning:** This process bypasses the normal email-based password reset mechanism, which could pose a security risk if not handled properly. Use this method only when necessary, ensure it is performed by trusted administrators, and always document the reason for the reset.
|
||||
|
||||
## How the password reset works
|
||||
|
||||
Palmr provides a CLI script that allows administrators to reset passwords directly within the Docker container. This script is designed to maintain security by enforcing interactive confirmation at every step, validating input data, and securely encrypting the new password using bcrypt with 10 salt rounds (consistent with the system's security standards). The script does not send email notifications, log invalid login attempts, or alter other user settings—it focuses solely on password reset.
|
||||
|
||||
## Step-by-step instructions
|
||||
|
||||
Follow these steps to reset a user password using the provided script. Ensure you have access to the Docker container before proceeding.
|
||||
|
||||
### 1. List Docker containers and identify the correct one
|
||||
|
||||
Before accessing the Palmr container, you need to identify its name or ID. Open a terminal on your host machine and list all running Docker containers by running the following command:
|
||||
|
||||
```bash
|
||||
docker ps
|
||||
```
|
||||
|
||||
This command will display a list of active containers, including their names, IDs, images, and other details. Look for the container running the Palmr application. If you used a specific name when setting up the container (e.g., `palmr-app`), it will appear under the `NAMES` column. If no name was specified, note the `CONTAINER ID` (a short string of characters) for the container associated with the Palmr image (likely something like `palmr` or a custom image name).
|
||||
|
||||
> **Note:** If you don't see the Palmr container, ensure it is running. You can start it using `docker start <container_name_or_id>` if it's stopped. If you're unsure about the setup, refer to the Palmr installation guide.
|
||||
|
||||
### 2. Access the Docker container
|
||||
|
||||
Once you've identified the correct container, access it by running the following command:
|
||||
|
||||
```bash
|
||||
docker exec -it <container_name_or_id> /bin/sh
|
||||
```
|
||||
|
||||
Replace `<container_name_or_id>` with the name or ID of your Palmr container. This command opens an interactive shell session inside the container, allowing you to execute commands directly.
|
||||
|
||||
### 3. Navigate to the server directory
|
||||
|
||||
Once inside the container, navigate to the server directory where the reset script is located:
|
||||
|
||||
```bash
|
||||
cd /app/server
|
||||
```
|
||||
|
||||
This directory contains the necessary scripts and configurations for managing Palmr's backend operations.
|
||||
|
||||
### 4. Run the password reset script
|
||||
|
||||
Execute the password reset script to start the interactive process:
|
||||
|
||||
```bash
|
||||
./reset-password.sh
|
||||
```
|
||||
|
||||
The script will prompt you to enter the email address of the user whose password you wish to reset. It will then display the user's information for verification, ask for confirmation to proceed, and request a new password (minimum 8 characters) which must be entered twice to ensure accuracy. Each step requires explicit confirmation to prevent accidental changes.
|
||||
|
||||
> **Note:** If you need to see a list of all users in the system before proceeding, you can run `./reset-password.sh --list`. For additional help, use `./reset-password.sh --help`.
|
||||
|
||||
### Example session
|
||||
|
||||
Below is an example of how the interactive session might look when running the script:
|
||||
|
||||
```
|
||||
$ ./reset-password.sh
|
||||
|
||||
Palmr Password Reset Tool
|
||||
===============================
|
||||
This script allows you to reset a user's password directly from the Docker terminal.
|
||||
WARNING: This bypasses normal security checks. Use only when necessary!
|
||||
|
||||
Enter user email: user@example.com
|
||||
|
||||
User found:
|
||||
Name: John Smith
|
||||
Username: john.smith
|
||||
Email: user@example.com
|
||||
Status: Active
|
||||
Admin: No
|
||||
|
||||
Do you want to reset the password for this user? (y/n): y
|
||||
|
||||
Enter new password requirements:
|
||||
- Minimum 8 characters
|
||||
|
||||
Enter new password: ********
|
||||
Confirm new password: ********
|
||||
|
||||
Hashing password...
|
||||
Updating password in database...
|
||||
Cleaning up existing password reset tokens...
|
||||
|
||||
Password reset successful!
|
||||
User: John Smith (user@example.com)
|
||||
The user can now login with the new password.
|
||||
|
||||
Security Note: The password has been encrypted using bcrypt with 10 salt rounds.
|
||||
```
|
||||
|
||||
## Troubleshooting common issues
|
||||
|
||||
If you encounter issues while running the script, refer to the following solutions to resolve common problems:
|
||||
|
||||
- **Error: "tsx is not available"**
|
||||
This error indicates missing dependencies. The script will attempt to install them automatically, but if it fails, manually install them by running:
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
# or
|
||||
npm install
|
||||
```
|
||||
|
||||
- **Error: "Prisma client not found"**
|
||||
This error occurs if the Prisma client is not generated. The script should handle this automatically, but if it fails, generate it manually with:
|
||||
|
||||
```bash
|
||||
npx prisma generate
|
||||
```
|
||||
|
||||
- **Error: "Database connection failed"**
|
||||
If the script cannot connect to the database, check the following:
|
||||
|
||||
- Ensure the database service is running within the container.
|
||||
- Confirm that the `prisma/palmr.db` file exists and has the correct permissions.
|
||||
- Verify that the container has access to the database volume.
|
||||
|
||||
- **Error: "Script must be run from server directory"**
|
||||
This error appears if you are not in the correct directory. Navigate to the server directory with:
|
||||
|
||||
```bash
|
||||
cd /app/server
|
||||
```
|
||||
|
||||
- **Error: "User not found"**
|
||||
If the email provided does not match any user, double-check the email address. You can list all users to find the correct one by running:
|
||||
|
||||
```bash
|
||||
./reset-password.sh --list
|
||||
```
|
||||
|
||||
Ensure the user exists in the system before attempting the reset.
|
||||
|
||||
- **Error: "Password does not meet requirements"**
|
||||
The new password must be at least 8 characters long. Ensure it meets this requirement and re-enter it carefully, confirming it matches the second entry.
|
||||
|
||||
- **Error: "Confirmation does not match"**
|
||||
If the two password entries do not match, the script will prompt you to try again. Ensure both entries are identical.
|
||||
|
||||
- **General Script Failure or Unexpected Behavior**
|
||||
If the script fails for an unknown reason, check the error message for details. Ensure your Palmr installation is up to date, and consider restarting the container if there are transient issues. If problems persist, consult the Palmr documentation or community for additional support.
|
||||
|
||||
## Security and best practices
|
||||
|
||||
To maintain the integrity and security of your Palmr instance while using this password reset method, adhere to the following guidelines:
|
||||
|
||||
- **Interactive Confirmation:** The script enforces interactive mode, requiring explicit confirmation at each step to prevent unauthorized or accidental resets. There are no shortcuts or automated options.
|
||||
- **Access Restriction:** Only administrators with direct access to the Docker container can use this script, ensuring that unauthorized users cannot reset passwords.
|
||||
- **Password Encryption:** New passwords are encrypted using bcrypt with 10 salt rounds, matching Palmr's standard security practices.
|
||||
- **Documentation and Notification:** Always document the date, time, and reason for performing a password reset. Notify the affected user through alternative means (if possible) to inform them of the change.
|
||||
- **Backup Recommendation:** Before using this script in a production environment, consider backing up your database to prevent data loss in case of an error.
|
||||
- **Post-Reset Actions:** After resetting a password, verify that the user can log in successfully and check system logs for any unusual activity related to the reset.
|
||||
- **Limit Usage:** Use this method sparingly and only in situations where SMTP-based reset is not an option. It is not intended for routine password management.
|
||||
- **Secure Environment:** Ensure that access to the Docker container and host machine is secured with strong passwords, restricted permissions, and, if possible, two-factor authentication to prevent unauthorized access to administrative tools.
|
||||
|
||||
> **Tip:** Treat this method as a last resort. Whenever possible, configure SMTP to enable the standard email-based password reset process, which provides an additional layer of security and user verification.
|
||||
|
||||
## Security philosophy
|
||||
|
||||
This script is built with a strong focus on security, prioritizing mandatory interactivity, multiple confirmations, and strict input validation. There are no "quick modes" or bypass options—every password reset requires careful and deliberate action from the administrator to ensure accountability and minimize risks.
|
258
apps/docs/content/docs/3.0-beta/quick-start.mdx
Normal file
@@ -0,0 +1,258 @@
|
||||
---
|
||||
title: Quick Start (Docker)
|
||||
icon: "Rocket"
|
||||
---
|
||||
|
||||
Welcome to the fastest way to deploy <span className="font-bold">Palmr.</span> - your secure, self-hosted file sharing solution. This guide will have you up and running in minutes, whether you're new to self-hosting or an experienced developer.
|
||||
|
||||
Palmr. offers flexible deployment options to match your infrastructure needs. This guide focuses on Docker deployment with our recommended filesystem storage, perfect for most use cases.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Ensure you have the following installed on your system:
|
||||
|
||||
- **Docker** - Container runtime ([installation guide](https://docs.docker.com/get-docker/))
|
||||
- **Docker Compose** - Multi-container orchestration ([installation guide](https://docs.docker.com/compose/install/))
|
||||
|
||||
> **Platform Support**: Palmr. is developed on macOS and extensively tested on Linux servers. While we haven't formally tested other platforms, Docker's cross-platform nature should ensure compatibility. Report any issues on our [GitHub repository](https://github.com/kyantech/Palmr/issues).
|
||||
|
||||
## Storage Options
|
||||
|
||||
Palmr. supports two storage approaches for persistent data:
|
||||
|
||||
### Named Volumes (Recommended)
|
||||
|
||||
**Best for**: Production environments, automated deployments
|
||||
|
||||
- ✅ **Managed by Docker**: No permission issues or manual path management
|
||||
- ✅ **Optimized Performance**: Docker-native storage optimization
|
||||
- ✅ **Cross-platform**: Consistent behavior across operating systems
|
||||
- ✅ **Simplified Backups**: Docker volume commands for backup/restore
|
||||
|
||||
### Bind Mounts
|
||||
|
||||
**Best for**: Development, direct file access requirements
|
||||
|
||||
- ✅ **Direct Access**: Files stored in local directory you specify
|
||||
- ✅ **Transparent Storage**: Direct filesystem access from host
|
||||
- ✅ **Custom Backup**: Use existing file system backup solutions
|
||||
- ⚠️ **Permission Considerations**: May require user/group configuration
|
||||
|
||||
---
|
||||
|
||||
## Option 1: Named Volumes (Recommended)
|
||||
|
||||
Named volumes provide the best performance and are managed entirely by Docker.
|
||||
|
||||
### Configuration
|
||||
|
||||
Use the provided `docker-compose.yaml` for named volumes:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
image: kyantech/palmr:latest
|
||||
container_name: palmr
|
||||
environment:
|
||||
- ENABLE_S3=false
|
||||
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars # CHANGE THIS KEY FOR SECURITY
|
||||
# - SECURE_SITE=false # Set to true if you are using a reverse proxy
|
||||
ports:
|
||||
- "5487:5487" # Web interface
|
||||
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY)
|
||||
volumes:
|
||||
- palmr_data:/app/server # Named volume for the application data
|
||||
restart: unless-stopped # Restart the container unless it is stopped
|
||||
|
||||
volumes:
|
||||
palmr_data:
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Option 2: Bind Mounts
|
||||
|
||||
Bind mounts store data in a local directory, providing direct file system access.
|
||||
|
||||
### Configuration
|
||||
|
||||
To use bind mounts, **replace the content** of your `docker-compose.yaml` with the following configuration (you can also reference `docker-compose-bind-mount-example.yaml` as a template):
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
image: kyantech/palmr:latest
|
||||
container_name: palmr
|
||||
environment:
|
||||
- ENABLE_S3=false
|
||||
- ENCRYPTION_KEY=change-this-key-in-production-min-32-chars # CHANGE THIS KEY FOR SECURITY
|
||||
# - SECURE_SITE=false # Set to true if you are using a reverse proxy
|
||||
# Optional: Set custom UID/GID for file permissions
|
||||
# - PALMR_UID=1000
|
||||
# - PALMR_GID=1000
|
||||
ports:
|
||||
- "5487:5487" # Web port
|
||||
- "3333:3333" # API port (OPTIONAL EXPOSED - ONLY IF YOU WANT TO ACCESS THE API DIRECTLY)
|
||||
volumes:
|
||||
# Bind mount for persistent data (uploads, database, temp files)
|
||||
- ./data:/app/server # Local directory for the application data
|
||||
restart: unless-stopped # Restart the container unless it is stopped
|
||||
```
|
||||
|
||||
### Deployment
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
> **Permission Configuration**: If you encounter permission issues with bind mounts (common on NAS systems), see our [UID/GID Configuration](/docs/3.0-beta/uid-gid-configuration) guide for automatic permission handling.
|
||||
|
||||
---
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Configure Palmr. behavior through environment variables:
|
||||
|
||||
| Variable | Default | Description |
|
||||
| ---------------- | ------- | ------------------------------------------------------- |
|
||||
| `ENABLE_S3` | `false` | Enable S3-compatible storage |
|
||||
| `ENCRYPTION_KEY` | - | **Required**: Minimum 32 characters for file encryption |
|
||||
| `SECURE_SITE` | `false` | Enable secure cookies for HTTPS/reverse proxy setups |
|
||||
|
||||
> **⚠️ Security Warning**: Always change the `ENCRYPTION_KEY` in production. This key encrypts your files - losing it makes files permanently inaccessible.
|
||||
|
||||
> **🔗 Reverse Proxy**: If deploying behind a reverse proxy (Traefik, Nginx, etc.), set `SECURE_SITE=true` and review our [Reverse Proxy Configuration](/docs/3.0-beta/reverse-proxy-configuration) guide for proper setup.
|
||||
|
||||
### Generate Secure Encryption Keys
|
||||
|
||||
Need a strong key for `ENCRYPTION_KEY`? Use our built-in generator to create cryptographically secure keys:
|
||||
|
||||
<KeyGenerator />
|
||||
|
||||
---
|
||||
|
||||
## Accessing Palmr.
|
||||
|
||||
Once deployed, access Palmr. through your web browser:
|
||||
|
||||
- **Local**: `http://localhost:5487`
|
||||
- **Server**: `http://YOUR_SERVER_IP:5487`
|
||||
|
||||
### API Access (Optional)
|
||||
|
||||
If you exposed port 3333 in your configuration, you can also access:
|
||||
|
||||
- **API Documentation**: `http://localhost:3333/docs` (local) or `http://YOUR_SERVER_IP:3333/docs` (server)
|
||||
- **API Endpoints**: Available at `http://localhost:3333` (local) or `http://YOUR_SERVER_IP:3333` (server)
|
||||
|
||||
> **📚 Learn More**: For complete API documentation, authentication, and integration examples, see our [API Reference](/docs/3.0-beta/api) guide.
|
||||
|
||||
> **💡 Production Tip**: For production deployments, configure HTTPS with a valid SSL certificate for enhanced security.
|
||||
|
||||
---
|
||||
|
||||
## Docker CLI Alternative
|
||||
|
||||
Prefer using Docker directly? Both storage options are supported:
|
||||
|
||||
**Named Volume:**
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name palmr \
|
||||
-e ENABLE_S3=false \
|
||||
-e ENCRYPTION_KEY=your-secure-key-min-32-chars \
|
||||
-p 5487:5487 \
|
||||
-p 3333:3333 \
|
||||
-v palmr_data:/app/server \
|
||||
--restart unless-stopped \
|
||||
kyantech/palmr:latest
|
||||
```
|
||||
|
||||
**Bind Mount:**
|
||||
|
||||
```bash
|
||||
docker run -d \
|
||||
--name palmr \
|
||||
-e ENABLE_S3=false \
|
||||
-e ENCRYPTION_KEY=your-secure-key-min-32-chars \
|
||||
-p 5487:5487 \
|
||||
-p 3333:3333 \
|
||||
-v $(pwd)/data:/app/server \
|
||||
--restart unless-stopped \
|
||||
kyantech/palmr:latest
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Updates
|
||||
|
||||
Keep Palmr. current with the latest features and security fixes:
|
||||
|
||||
```bash
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
### Backup & Restore
|
||||
|
||||
The backup method depends on which storage option you're using:
|
||||
|
||||
**Named Volume Backup:**
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
-v palmr_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar czf /backup/palmr-backup.tar.gz -C /data .
|
||||
```
|
||||
|
||||
**Named Volume Restore:**
|
||||
|
||||
```bash
|
||||
docker run --rm \
|
||||
-v palmr_data:/data \
|
||||
-v $(pwd):/backup \
|
||||
alpine tar xzf /backup/palmr-backup.tar.gz -C /data
|
||||
```
|
||||
|
||||
**Bind Mount Backup:**
|
||||
|
||||
```bash
|
||||
tar czf palmr-backup.tar.gz ./data
|
||||
```
|
||||
|
||||
**Bind Mount Restore:**
|
||||
|
||||
```bash
|
||||
tar xzf palmr-backup.tar.gz
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
Your Palmr. instance is now ready! Explore additional configuration options:
|
||||
|
||||
### Advanced Configuration
|
||||
|
||||
- **[UID/GID Configuration](/docs/3.0-beta/uid-gid-configuration)** - Configure user permissions for NAS systems and custom environments
|
||||
- **[S3 Storage](/docs/3.0-beta/s3-configuration)** - Scale with Amazon S3 or compatible storage providers
|
||||
- **[Manual Installation](/docs/3.0-beta/manual-installation)** - Manual installation and custom configurations
|
||||
|
||||
### Integration & Development
|
||||
|
||||
- **[API Reference](/docs/3.0-beta/api)** - Integrate Palmr. with your applications
|
||||
- **[Architecture Guide](/docs/3.0-beta/architecture)** - Understanding Palmr. components and design
|
||||
|
||||
---
|
||||
|
||||
Need help? Visit our [GitHub Issues](https://github.com/kyantech/Palmr/issues) or community discussions.
|
199
apps/docs/content/docs/3.0-beta/reverse-proxy-configuration.mdx
Normal file
@@ -0,0 +1,199 @@
|
||||
---
|
||||
title: Reverse Proxy Configuration
|
||||
icon: "Shield"
|
||||
---
|
||||
|
||||
When deploying **Palmr.** behind a reverse proxy (like Traefik, Nginx, or Cloudflare), you need to configure secure cookie settings to ensure proper authentication. This guide covers the `SECURE_SITE` environment variable and related proxy configurations.
|
||||
|
||||
## Overview
|
||||
|
||||
Reverse proxies terminate SSL/TLS connections and forward requests to Palmr., which can cause authentication issues if cookies aren't configured properly for HTTPS environments. The `SECURE_SITE` environment variable controls cookie security settings to handle these scenarios.
|
||||
|
||||
## The SECURE_SITE Environment Variable
|
||||
|
||||
The `SECURE_SITE` variable configures how Palmr. handles authentication cookies based on your deployment environment:
|
||||
|
||||
### Configuration Options
|
||||
|
||||
| Value | Cookie Settings | Use Case |
|
||||
| ------- | ------------------------------------- | ----------------------------------- |
|
||||
| `true` | `secure: true`, `sameSite: "lax"` | HTTPS/Production with reverse proxy |
|
||||
| `false` | `secure: false`, `sameSite: "strict"` | HTTP/Development (default) |
|
||||
|
||||
### When to Use SECURE_SITE=true
|
||||
|
||||
Set `SECURE_SITE=true` in the following scenarios:
|
||||
|
||||
- ✅ **Reverse Proxy with HTTPS**: Traefik, Nginx, HAProxy with SSL termination
|
||||
- ✅ **Cloud Providers**: Cloudflare, AWS ALB, Azure Application Gateway
|
||||
- ✅ **CDN with HTTPS**: Any CDN that terminates SSL
|
||||
- ✅ **Production Deployments**: When users access via HTTPS
|
||||
|
||||
### When to Use SECURE_SITE=false
|
||||
|
||||
Keep `SECURE_SITE=false` (default) for:
|
||||
|
||||
- ✅ **Local Development**: Running on `http://localhost`
|
||||
- ✅ **Direct HTTP Access**: No reverse proxy involved
|
||||
- ✅ **Testing Environments**: When using HTTP
|
||||
- ✅ **HTTP Reverse Proxy**: Nginx, Apache, etc. without SSL termination
|
||||
|
||||
---
|
||||
|
||||
## HTTP Reverse Proxy Setup
|
||||
|
||||
**Docker Compose for HTTP Nginx:**
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- SECURE_SITE=false # HTTP = false
|
||||
```
|
||||
|
||||
> **⚠️ HTTP Security**: Remember that HTTP transmits data in plain text. Consider using HTTPS in production environments.
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting Authentication Issues
|
||||
|
||||
### Common Symptoms
|
||||
|
||||
If you experience authentication issues behind a reverse proxy:
|
||||
|
||||
- ❌ Login appears successful but redirects to login page
|
||||
- ❌ "No Authorization was found in request.cookies" errors
|
||||
- ❌ API requests return 401 Unauthorized
|
||||
- ❌ User registration fails silently
|
||||
|
||||
### Diagnostic Steps
|
||||
|
||||
1. **Check Browser Developer Tools**:
|
||||
|
||||
- Look for cookies in Application/Storage tab
|
||||
- Verify cookie has `Secure` flag when using HTTPS
|
||||
- Check if `SameSite` attribute is appropriate
|
||||
|
||||
2. **Verify Environment Variables**:
|
||||
|
||||
```bash
|
||||
docker exec -it palmr env | grep SECURE_SITE
|
||||
```
|
||||
|
||||
3. **Test Cookie Settings**:
|
||||
- With `SECURE_SITE=false`: Should work on HTTP
|
||||
- With `SECURE_SITE=true`: Should work on HTTPS
|
||||
|
||||
### Common Fixes
|
||||
|
||||
**Problem**: Authentication fails with reverse proxy
|
||||
|
||||
**Solution**: Set `SECURE_SITE=true` and ensure proper headers:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- SECURE_SITE=true
|
||||
```
|
||||
|
||||
**Problem**: Mixed content errors
|
||||
|
||||
**Solution**: Ensure proxy passes correct headers:
|
||||
|
||||
```yaml
|
||||
# Traefik
|
||||
- "traefik.http.middlewares.palmr-headers.headers.customrequestheaders.X-Forwarded-Proto=https"
|
||||
|
||||
# Nginx
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
```
|
||||
|
||||
**Problem**: Authentication fails with HTTP reverse proxy
|
||||
|
||||
**Solution**: Use `SECURE_SITE=false` and ensure proper cookie headers:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- SECURE_SITE=false # For HTTP proxy
|
||||
```
|
||||
|
||||
```nginx
|
||||
# Nginx - Add these headers for cookie handling
|
||||
proxy_set_header Cookie $http_cookie;
|
||||
proxy_pass_header Set-Cookie;
|
||||
```
|
||||
|
||||
**Problem**: SQLite "readonly database" error with bind mounts
|
||||
|
||||
**Solution**: Configure proper UID/GID permissions:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- PALMR_UID=1000 # Your host UID (check with: id)
|
||||
- PALMR_GID=1000 # Your host GID
|
||||
- ENCRYPTION_KEY=your-key-here
|
||||
```
|
||||
|
||||
> **💡 Note**: Check your host UID/GID with `id` command and use those values. See [UID/GID Configuration](/docs/3.0-beta/uid-gid-configuration) for detailed setup.
|
||||
|
||||
---
|
||||
|
||||
## Security Considerations
|
||||
|
||||
> **⚠️ Important**: Always use HTTPS in production environments. The `SECURE_SITE=true` setting ensures cookies are only sent over encrypted connections.
|
||||
|
||||
---
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
### Multiple Domains
|
||||
|
||||
If serving Palmr. on multiple domains, ensure consistent cookie settings:
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- SECURE_SITE=true # Use for all HTTPS domains
|
||||
```
|
||||
|
||||
### Development vs Production
|
||||
|
||||
Use environment-specific configurations:
|
||||
|
||||
**Development (HTTP):**
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- SECURE_SITE=false
|
||||
```
|
||||
|
||||
**Production (HTTPS):**
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
- SECURE_SITE=true
|
||||
```
|
||||
|
||||
### Health Checks
|
||||
|
||||
Add health checks to ensure proper proxy configuration:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
# ... other config
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:5487/api/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Need Help?
|
||||
|
||||
If you're still experiencing issues after following this guide:
|
||||
|
||||
1. **Check the Logs**: `docker logs palmr`
|
||||
2. **Verify Headers**: Use browser dev tools or `curl -I`
|
||||
3. **Test Direct Access**: Try accessing Palmr. directly (bypassing proxy)
|
||||
4. **Open an Issue**: [Report bugs on GitHub](https://github.com/kyantech/Palmr/issues)
|
||||
|
||||
> **💡 Pro Tip**: When reporting issues, include your reverse proxy configuration and any relevant error messages from both Palmr. and your proxy logs.
|
247
apps/docs/content/docs/3.0-beta/s3-providers.mdx
Normal file
@@ -0,0 +1,247 @@
|
||||
---
|
||||
title: S3 Providers
|
||||
icon: Package
|
||||
---
|
||||
|
||||
This guide provides comprehensive configuration instructions for integrating Palmr. with various S3-compatible storage providers. Whether you're using cloud services like AWS S3 or self-hosted solutions like MinIO, this guide will help you set up reliable object storage for your files.
|
||||
|
||||
> **Overview:** Palmr. supports any S3-compatible storage provider, giving you flexibility to choose the solution that best fits your needs and budget.
|
||||
|
||||
## When to use S3-compatible storage
|
||||
|
||||
Consider using S3-compatible storage when you need:
|
||||
|
||||
- **Cloud storage** for distributed deployments
|
||||
- **Scalability** beyond local filesystem limitations
|
||||
- **Redundancy** and backup capabilities
|
||||
- **CDN integration** for faster file delivery
|
||||
- **Multi-region** file distribution
|
||||
|
||||
## Environment variables
|
||||
|
||||
To enable S3-compatible storage, set `ENABLE_S3=true` and configure the following environment variables:
|
||||
|
||||
| Variable | Description | Required | Default |
|
||||
| --------------------- | ----------------------------- | -------- | ----------------- |
|
||||
| `S3_ENDPOINT` | S3 provider endpoint URL | Yes | - |
|
||||
| `S3_PORT` | Connection port | No | Based on protocol |
|
||||
| `S3_USE_SSL` | Enable SSL/TLS encryption | Yes | `true` |
|
||||
| `S3_ACCESS_KEY` | Access key for authentication | Yes | - |
|
||||
| `S3_SECRET_KEY` | Secret key for authentication | Yes | - |
|
||||
| `S3_REGION` | Storage region | Yes | - |
|
||||
| `S3_BUCKET_NAME` | Bucket/container name | Yes | - |
|
||||
| `S3_FORCE_PATH_STYLE` | Use path-style URLs | No | `false` |
|
||||
|
||||
## Provider configurations
|
||||
|
||||
Below are tested configurations for popular S3-compatible providers. Replace the example values with your actual credentials and settings.
|
||||
|
||||
> **Security Note:** Never commit real credentials to version control. Use environment files or secure secret management systems.
|
||||
|
||||
### AWS S3
|
||||
|
||||
Amazon S3 is the original S3 service, offering global availability and extensive features.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=s3.amazonaws.com
|
||||
S3_USE_SSL=true
|
||||
S3_ACCESS_KEY=your-access-key-id
|
||||
S3_SECRET_KEY=your-secret-access-key
|
||||
S3_REGION=us-east-1
|
||||
S3_BUCKET_NAME=your-bucket-name
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
```
|
||||
|
||||
**Getting credentials:**
|
||||
|
||||
1. Go to AWS IAM Console
|
||||
2. Create a new user with S3 permissions
|
||||
3. Generate access keys for programmatic access
|
||||
|
||||
### MinIO (Self-hosted)
|
||||
|
||||
MinIO is perfect for self-hosted deployments and development environments.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=localhost
|
||||
S3_PORT=9000
|
||||
S3_USE_SSL=false
|
||||
S3_ACCESS_KEY=your-minio-access-key
|
||||
S3_SECRET_KEY=your-minio-secret-key
|
||||
S3_REGION=us-east-1
|
||||
S3_BUCKET_NAME=your-bucket-name
|
||||
S3_FORCE_PATH_STYLE=true
|
||||
```
|
||||
|
||||
**Setup notes:**
|
||||
|
||||
- Use `S3_FORCE_PATH_STYLE=true` for MinIO
|
||||
- Default MinIO port is 9000
|
||||
- SSL can be disabled for local development
|
||||
|
||||
### Google Cloud Storage
|
||||
|
||||
Google Cloud Storage offers competitive pricing and global infrastructure.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=storage.googleapis.com
|
||||
S3_USE_SSL=true
|
||||
S3_ACCESS_KEY=your-hmac-access-id
|
||||
S3_SECRET_KEY=your-hmac-secret
|
||||
S3_REGION=us-central1
|
||||
S3_BUCKET_NAME=your-bucket-name
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
```
|
||||
|
||||
**Getting credentials:**
|
||||
|
||||
1. Enable Cloud Storage API in Google Cloud Console
|
||||
2. Create HMAC keys for S3 compatibility
|
||||
3. Use the generated access ID and secret
|
||||
|
||||
### DigitalOcean Spaces
|
||||
|
||||
DigitalOcean Spaces provides simple, scalable object storage.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=nyc3.digitaloceanspaces.com
|
||||
S3_USE_SSL=true
|
||||
S3_ACCESS_KEY=your-spaces-access-key
|
||||
S3_SECRET_KEY=your-spaces-secret-key
|
||||
S3_REGION=nyc3
|
||||
S3_BUCKET_NAME=your-space-name
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
```
|
||||
|
||||
**Available regions:**
|
||||
|
||||
- `nyc3` (New York)
|
||||
- `ams3` (Amsterdam)
|
||||
- `sgp1` (Singapore)
|
||||
- `fra1` (Frankfurt)
|
||||
|
||||
### Backblaze B2
|
||||
|
||||
Backblaze B2 offers cost-effective storage with S3-compatible API.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=s3.us-west-002.backblazeb2.com
|
||||
S3_USE_SSL=true
|
||||
S3_ACCESS_KEY=your-key-id
|
||||
S3_SECRET_KEY=your-application-key
|
||||
S3_REGION=us-west-002
|
||||
S3_BUCKET_NAME=your-bucket-name
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
```
|
||||
|
||||
**Cost advantage:**
|
||||
|
||||
- Significantly lower storage costs
|
||||
- Free egress to Cloudflare CDN
|
||||
- Pay-as-you-go pricing model
|
||||
|
||||
### Wasabi
|
||||
|
||||
Wasabi provides hot cloud storage with predictable pricing.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=s3.wasabisys.com
|
||||
S3_USE_SSL=true
|
||||
S3_ACCESS_KEY=your-access-key
|
||||
S3_SECRET_KEY=your-secret-key
|
||||
S3_REGION=us-east-1
|
||||
S3_BUCKET_NAME=your-bucket-name
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
```
|
||||
|
||||
**Benefits:**
|
||||
|
||||
- No egress fees
|
||||
- Fast performance
|
||||
- Simple pricing structure
|
||||
|
||||
### Azure Blob Storage
|
||||
|
||||
Azure Blob Storage with S3-compatible API for Microsoft ecosystem integration.
|
||||
|
||||
```bash
|
||||
ENABLE_S3=true
|
||||
S3_ENDPOINT=your-account.blob.core.windows.net
|
||||
S3_USE_SSL=true
|
||||
S3_ACCESS_KEY=your-access-key
|
||||
S3_SECRET_KEY=your-secret-key
|
||||
S3_REGION=eastus
|
||||
S3_BUCKET_NAME=your-container-name
|
||||
S3_FORCE_PATH_STYLE=false
|
||||
```
|
||||
|
||||
**Setup requirements:**
|
||||
|
||||
- Enable S3-compatible API in Azure
|
||||
- Use container name as bucket name
|
||||
- Configure appropriate access policies
|
||||
|
||||
## Configuration best practices
|
||||
|
||||
### Security considerations
|
||||
|
||||
- **Use IAM policies** to limit access to specific buckets and operations
|
||||
- **Enable encryption** at rest and in transit
|
||||
- **Rotate credentials** regularly
|
||||
- **Monitor access logs** for unusual activity
|
||||
- **Use HTTPS** for all connections (`S3_USE_SSL=true`)
|
||||
|
||||
### Performance optimization
|
||||
|
||||
- **Choose regions** close to your users or server location
|
||||
- **Configure CDN** for faster file delivery
|
||||
- **Use appropriate bucket policies** for public file access
|
||||
- **Monitor bandwidth** usage and costs
|
||||
|
||||
### Troubleshooting common issues
|
||||
|
||||
**Connection errors:**
|
||||
|
||||
- Verify endpoint URL and port settings
|
||||
- Check firewall and network connectivity
|
||||
- Ensure SSL/TLS settings match provider requirements
|
||||
|
||||
**Authentication failures:**
|
||||
|
||||
- Confirm access key and secret key are correct
|
||||
- Verify IAM permissions for bucket operations
|
||||
- Check if credentials have expired
|
||||
|
||||
**Bucket access issues:**
|
||||
|
||||
- Ensure bucket exists and is accessible
|
||||
- Verify region settings match bucket location
|
||||
- Check bucket policies and ACL settings
|
||||
|
||||
## Testing your configuration
|
||||
|
||||
After configuring your S3 provider, test the connection by:
|
||||
|
||||
1. **Upload a test file** through the Palmr. interface
|
||||
2. **Verify file appears** in your S3 bucket
|
||||
3. **Download the file** to confirm retrieval works
|
||||
4. **Check file permissions** and access controls
|
||||
|
||||
> **Tip:** Start with a development bucket to test your configuration before using production storage.
|
||||
|
||||
## Switching between providers
|
||||
|
||||
To switch from filesystem to S3 storage or between S3 providers:
|
||||
|
||||
1. **Backup existing files** if switching from filesystem storage
|
||||
2. **Update environment variables** with new provider settings
|
||||
3. **Restart the Palmr. container** to apply changes
|
||||
4. **Test file operations** to ensure everything works correctly
|
||||
|
||||
Remember that existing files won't be automatically migrated when switching storage providers.
|
141
apps/docs/content/docs/3.0-beta/screenshots.mdx
Normal file
@@ -0,0 +1,141 @@
|
||||
---
|
||||
title: Screenshots
|
||||
icon: Image
|
||||
---
|
||||
|
||||
import { ZoomableImage } from "@/components/ui/zoomable-image";
|
||||
|
||||
## Screenshots
|
||||
|
||||
Here you can find a collection of screenshots showcasing various features and interfaces of the Palmr. web application. These images provide a visual overview of the user experience, highlighting key functionalities such as file sharing, user management, and settings configuration. Explore the screenshots below to get a better understanding of how Palmr works and what to expect from the platform.
|
||||
|
||||
> **Note:** All screenshots shown are taken in dark mode, but Palmr. also offers a light mode theme for users who prefer brighter interfaces.
|
||||
|
||||
### Authentication & Access
|
||||
|
||||
#### Home page
|
||||
|
||||
The main landing page where users can access the platform and learn about Palmr.'s features.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/home.png"
|
||||
alt="Home Page - Main landing page of Palmr"
|
||||
/>
|
||||
|
||||
#### Login page
|
||||
|
||||
Secure authentication interface where users enter their credentials to access their Palmr account.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/login.png"
|
||||
alt="Login Page - User authentication interface"
|
||||
/>
|
||||
|
||||
#### Forgot password
|
||||
|
||||
Password recovery interface that allows users to reset their passwords when they can't access their accounts.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/forgot-password.png"
|
||||
alt="Forgot Password - Password recovery interface"
|
||||
/>
|
||||
|
||||
### Main Application Interface
|
||||
|
||||
#### Dashboard
|
||||
|
||||
The central hub after login, providing an overview of recent activity, quick actions, and system status.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/dashboard.png"
|
||||
alt="Dashboard - Main application hub with overview and quick actions"
|
||||
/>
|
||||
|
||||
### File Management
|
||||
|
||||
#### Files list view
|
||||
|
||||
Comprehensive file browser displaying all uploaded files in a detailed list format with metadata, actions, and sorting options.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/files-list.png"
|
||||
alt="Files List View - Detailed file browser with metadata and actions"
|
||||
/>
|
||||
|
||||
#### Files card view
|
||||
|
||||
Alternative file browser layout showing files as visual cards, perfect for quick browsing and visual file identification.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/files-card.png"
|
||||
alt="Files Card View - Visual card-based file browser layout"
|
||||
/>
|
||||
|
||||
#### Receive files
|
||||
|
||||
File upload interface where users can drag and drop or select files to upload to their Palmr storage.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/receive-files.png"
|
||||
alt="Receive Files - File upload interface with drag and drop functionality"
|
||||
/>
|
||||
|
||||
### Sharing & Collaboration
|
||||
|
||||
#### Shares page
|
||||
|
||||
Management interface for all shared files and folders, showing share status, permissions, and access controls.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/shares.png"
|
||||
alt="Shares Page - Share management with permissions and access controls"
|
||||
/>
|
||||
|
||||
### User & System Management
|
||||
|
||||
#### User management
|
||||
|
||||
Administrative interface for managing user accounts, permissions, roles, and system access controls.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/user-management.png"
|
||||
alt="User Management - Administrative interface for user accounts and permissions"
|
||||
/>
|
||||
|
||||
#### Profile settings
|
||||
|
||||
Personal account management where users can update their profile information, preferences, and account settings.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/profile.png"
|
||||
alt="Profile Settings - Personal account management and preferences"
|
||||
/>
|
||||
|
||||
#### System settings
|
||||
|
||||
Comprehensive system configuration interface for administrators to manage platform settings, integrations, and system behavior.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/settings.png"
|
||||
alt="System Settings - Administrative configuration interface"
|
||||
/>
|
||||
|
||||
### Reverse share page themes
|
||||
|
||||
#### WeTransfer theme
|
||||
|
||||
Special sharing interface with WeTransfer-inspired design, providing a familiar experience for file sharing with custom theming.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/wetransfer.png"
|
||||
alt="WeTransfer Theme - WeTransfer-inspired sharing interface with custom theming"
|
||||
/>
|
||||
|
||||
#### Default reverse theme
|
||||
|
||||
Alternative dark theme interface showing Palmr's theming capabilities and customization options for different user preferences.
|
||||
|
||||
<ZoomableImage
|
||||
src="/assets/v3/screenshots/default-reverse.png"
|
||||
alt="Default Reverse Theme - Dark theme interface showcasing customization options"
|
||||
/>
|
443
apps/docs/content/docs/3.0-beta/translation-management.mdx
Normal file
@@ -0,0 +1,443 @@
|
||||
---
|
||||
title: Translation Management
|
||||
icon: Languages
|
||||
---
|
||||
|
||||
import { Tab, Tabs } from "fumadocs-ui/components/tabs";
|
||||
import { Callout } from "fumadocs-ui/components/callout";
|
||||
|
||||
Palmr includes a comprehensive translation key management system that automates synchronization and validation of the application's internationalization files.
|
||||
|
||||
## Overview
|
||||
|
||||
The translation management system consists of Python scripts that help maintain consistency across all supported languages:
|
||||
|
||||
- **Synchronization**: Automatically add missing translation keys
|
||||
- **Validation**: Check translation status and completeness
|
||||
- **Key Management**: Manage translation keys structure and consistency
|
||||
- **Reporting**: Generate detailed translation reports
|
||||
|
||||
## Quick Start
|
||||
|
||||
<Tabs items={['npm/pnpm', 'Python Direct']}>
|
||||
<Tab value="npm/pnpm">
|
||||
```bash
|
||||
# Complete workflow (recommended)
|
||||
pnpm run translations
|
||||
|
||||
# Check translation status
|
||||
pnpm run translations:check
|
||||
|
||||
# Synchronize missing keys
|
||||
pnpm run translations:sync
|
||||
|
||||
# Test workflow without changes (dry run)
|
||||
pnpm run translations:dry-run
|
||||
|
||||
# Show help
|
||||
pnpm run translations:help
|
||||
```
|
||||
|
||||
</Tab>
|
||||
<Tab value="Python Direct">
|
||||
```bash
|
||||
cd apps/web/scripts
|
||||
|
||||
# Complete workflow (recommended)
|
||||
python3 run_translations.py all
|
||||
|
||||
# Individual commands
|
||||
python3 run_translations.py check
|
||||
python3 run_translations.py sync
|
||||
python3 run_translations.py all --dry-run
|
||||
python3 run_translations.py help
|
||||
```
|
||||
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Available Scripts
|
||||
|
||||
### Main Commands (npm/pnpm)
|
||||
|
||||
| Command | Description |
|
||||
| ------------------------------- | ----------------------------------------- |
|
||||
| `pnpm run translations` | Complete workflow: sync + check |
|
||||
| `pnpm run translations:check` | Check translation status and completeness |
|
||||
| `pnpm run translations:sync` | Synchronize missing keys from en-US.json |
|
||||
| `pnpm run translations:dry-run` | Test workflow without making changes |
|
||||
| `pnpm run translations:help` | Show detailed help and examples |
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Adding New Translation Keys
|
||||
|
||||
When you add new text to the application:
|
||||
|
||||
1. **Add to English**: Update `apps/web/messages/en-US.json` with your new keys
|
||||
2. **Sync translations**: Run `pnpm run translations:sync` to add missing keys to all languages
|
||||
3. **Manual translation**: Translate strings marked with `[TO_TRANSLATE]` manually
|
||||
4. **Test in UI**: Verify translations work correctly in the application interface
|
||||
|
||||
<Callout type="important">
|
||||
**Manual translation required**: All strings marked with `[TO_TRANSLATE]` must
|
||||
be manually translated by native speakers or professional translators for
|
||||
accuracy.
|
||||
</Callout>
|
||||
|
||||
### 2. Checking Translation Status
|
||||
|
||||
<Callout>
|
||||
Always run `pnpm run translations:check` before releases to ensure
|
||||
completeness.
|
||||
</Callout>
|
||||
|
||||
```bash
|
||||
# Generate detailed translation report
|
||||
pnpm run translations:check
|
||||
```
|
||||
|
||||
The report shows:
|
||||
|
||||
- **Completeness percentage** for each language
|
||||
- **Untranslated strings** marked with `[TO_TRANSLATE]`
|
||||
- **Identical strings** that may need localization
|
||||
- **Missing keys** compared to English reference
|
||||
|
||||
### 3. Manual Translation Process
|
||||
|
||||
For all translation strings:
|
||||
|
||||
1. **Find untranslated strings**: Look for `[TO_TRANSLATE] Original text` in language files
|
||||
2. **Replace with translation**: Remove the prefix and add proper translation
|
||||
3. **Validate**: Run `pnpm run translations:check` to verify completeness
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
apps/web/
|
||||
├── messages/ # Translation files
|
||||
│ ├── en-US.json # Reference language (English)
|
||||
│ ├── pt-BR.json # Portuguese (Brazil)
|
||||
│ ├── es-ES.json # Spanish
|
||||
│ └── ... # Other languages
|
||||
│
|
||||
└── scripts/ # Management scripts
|
||||
├── run_translations.py # Main wrapper
|
||||
├── sync_translations.py # Synchronization
|
||||
├── check_translations.py # Status checking
|
||||
└── clean_translations.py # Cleanup utilities
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- **Python 3.6 or higher** - Required for running the translation scripts
|
||||
- **No external dependencies** - Scripts use only Python standard libraries
|
||||
- **UTF-8 support** - Ensure your terminal supports UTF-8 for proper display of translations
|
||||
|
||||
## Script Details
|
||||
|
||||
### Main Wrapper (`run_translations.py`)
|
||||
|
||||
The main script provides a unified interface for all translation operations:
|
||||
|
||||
#### Available Commands
|
||||
|
||||
- `check` - Check translation status and generate reports
|
||||
- `sync` - Synchronize missing keys from reference language
|
||||
- `all` - Run complete workflow (sync + check)
|
||||
- `help` - Show detailed help with examples
|
||||
|
||||
#### How it Works
|
||||
|
||||
1. Validates parameters and working directory
|
||||
2. Calls appropriate individual scripts with passed parameters
|
||||
3. Provides unified error handling and progress reporting
|
||||
4. Supports all parameters from individual scripts
|
||||
|
||||
### Synchronization Script (`sync_translations.py`)
|
||||
|
||||
Maintains consistency across all language files:
|
||||
|
||||
#### Process
|
||||
|
||||
1. **Load reference**: Reads `en-US.json` as source of truth
|
||||
2. **Scan languages**: Finds all `*.json` files in messages directory
|
||||
3. **Compare keys**: Identifies missing keys in each language file
|
||||
4. **Add missing keys**: Copies structure from reference with `[TO_TRANSLATE]` prefix
|
||||
5. **Save updates**: Maintains JSON formatting and UTF-8 encoding
|
||||
|
||||
#### Key Features
|
||||
|
||||
- **Recursive key detection**: Handles nested JSON objects
|
||||
- **Safe updates**: Preserves existing translations
|
||||
- **Consistent formatting**: Maintains proper JSON structure
|
||||
- **Progress reporting**: Shows detailed sync results
|
||||
|
||||
### Status Check Script (`check_translations.py`)
|
||||
|
||||
Provides comprehensive translation analysis:
|
||||
|
||||
#### Generated Reports
|
||||
|
||||
- **Completion percentage**: How much of each language is translated
|
||||
- **Untranslated count**: Strings still marked with `[TO_TRANSLATE]`
|
||||
- **Identical strings**: Text identical to English (may need localization)
|
||||
- **Missing keys**: Keys present in reference but not in target language
|
||||
|
||||
#### Analysis Features
|
||||
|
||||
- **Visual indicators**: Icons show completion status (✅ 🟡 🔴)
|
||||
- **Detailed breakdowns**: Per-language analysis with specific keys
|
||||
- **Quality insights**: Identifies potential translation issues
|
||||
- **Export friendly**: Output can be redirected to files for reports
|
||||
|
||||
## Advanced Usage
|
||||
|
||||
### Custom Parameters
|
||||
|
||||
You can pass additional parameters to the underlying Python scripts for more control:
|
||||
|
||||
#### Synchronization Parameters (`sync`)
|
||||
|
||||
```bash
|
||||
# Sync without marking new keys as [TO_TRANSLATE]
|
||||
python3 scripts/run_translations.py sync --no-mark-untranslated
|
||||
|
||||
# Use a different reference file (default: en-US.json)
|
||||
python3 scripts/run_translations.py sync --reference pt-BR.json
|
||||
|
||||
# Specify custom messages directory
|
||||
python3 scripts/run_translations.py sync --messages-dir /path/to/messages
|
||||
|
||||
# Dry run mode - see what would be changed
|
||||
python3 scripts/run_translations.py sync --dry-run
|
||||
```
|
||||
|
||||
#### Check Parameters (`check`)
|
||||
|
||||
```bash
|
||||
# Use different reference file for comparison
|
||||
python3 scripts/run_translations.py check --reference pt-BR.json
|
||||
|
||||
# Check translations in custom directory
|
||||
python3 scripts/run_translations.py check --messages-dir /path/to/messages
|
||||
```
|
||||
|
||||
### Parameter Reference
|
||||
|
||||
| Parameter | Commands | Description |
|
||||
| ------------------------ | --------------- | --------------------------------------------- |
|
||||
| `--dry-run` | `sync`, `all` | Preview changes without modifying files |
|
||||
| `--messages-dir` | All | Custom directory containing translation files |
|
||||
| `--reference` | `sync`, `check` | Reference file to use (default: en-US.json) |
|
||||
| `--no-mark-untranslated` | `sync` | Don't add [TO_TRANSLATE] prefix to new keys |
|
||||
|
||||
### Dry Run Mode
|
||||
|
||||
Always test changes first:
|
||||
|
||||
```bash
|
||||
# Test complete workflow (recommended)
|
||||
pnpm run translations:dry-run
|
||||
|
||||
# Alternative: Direct Python commands
|
||||
python3 scripts/run_translations.py all --dry-run
|
||||
python3 scripts/run_translations.py sync --dry-run
|
||||
```
|
||||
|
||||
### Common Use Cases
|
||||
|
||||
#### Scenario 1: Adding Keys Without Marking for Translation
|
||||
|
||||
```bash
|
||||
# Sync new keys without auto-marking for translation
|
||||
python3 scripts/run_translations.py sync --no-mark-untranslated
|
||||
|
||||
# Manually mark specific keys that need translation
|
||||
# Edit files to add [TO_TRANSLATE] prefix where needed
|
||||
```
|
||||
|
||||
#### Scenario 2: Custom Project Structure
|
||||
|
||||
```bash
|
||||
# Work with translations in different directory
|
||||
python3 scripts/run_translations.py all --messages-dir ../custom-translations
|
||||
```
|
||||
|
||||
#### Scenario 3: Quality Assurance
|
||||
|
||||
```bash
|
||||
# Use different language as reference for comparison
|
||||
python3 scripts/run_translations.py check --reference pt-BR.json
|
||||
|
||||
# This helps identify inconsistencies when you have high-quality translations
|
||||
```
|
||||
|
||||
## Translation Keys Format
|
||||
|
||||
Translation files use nested JSON structure:
|
||||
|
||||
```json
|
||||
{
|
||||
"common": {
|
||||
"actions": {
|
||||
"save": "Save",
|
||||
"cancel": "Cancel",
|
||||
"delete": "Delete"
|
||||
},
|
||||
"messages": {
|
||||
"success": "Operation completed successfully",
|
||||
"error": "An error occurred"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
"welcome": "Welcome to Palmr"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Manual Translation
|
||||
|
||||
<Callout type="warning">
|
||||
**Professional translation recommended**: For production applications,
|
||||
consider using professional translation services or native speakers to ensure
|
||||
high-quality, culturally appropriate translations.
|
||||
</Callout>
|
||||
|
||||
The system marks strings that need translation with the `[TO_TRANSLATE]` prefix:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "[TO_TRANSLATE] Original English text"
|
||||
}
|
||||
```
|
||||
|
||||
After manual translation:
|
||||
|
||||
```json
|
||||
{
|
||||
"key": "Texto original em inglês"
|
||||
}
|
||||
```
|
||||
|
||||
### Translation Review Process
|
||||
|
||||
1. **Identify**: Use `pnpm run translations:check` to find untranslated strings
|
||||
2. **Translate**: Replace `[TO_TRANSLATE]` strings with proper translations
|
||||
3. **Review**: Check each translation for:
|
||||
- **Context accuracy**: Does it make sense in the UI?
|
||||
- **Technical terms**: Are they correctly translated?
|
||||
- **Tone consistency**: Matches the application's voice?
|
||||
- **Cultural appropriateness**: Suitable for target audience?
|
||||
4. **Test**: Verify translations in the actual application interface
|
||||
5. **Document**: Note any translation decisions for future reference
|
||||
|
||||
### Common Review Points
|
||||
|
||||
- **Button labels**: Ensure they fit within UI constraints
|
||||
- **Error messages**: Must be clear and helpful to users
|
||||
- **Navigation items**: Should be intuitive in target language
|
||||
- **Technical terms**: Some may be better left in English
|
||||
- **Placeholders**: Maintain formatting and variable names
|
||||
|
||||
## Development Guidelines
|
||||
|
||||
<Callout type="important">
|
||||
**Primary Language**: Always use `en-US.json` as the parent language for
|
||||
development. All new translation keys must be added to English first.
|
||||
</Callout>
|
||||
|
||||
### Translation Workflow for Development
|
||||
|
||||
1. **English First**: Add all new text to `apps/web/messages/en-US.json`
|
||||
2. **Sync keys**: Use scripts to generate key structure for other languages
|
||||
3. **Manual translation**: All strings must be manually translated for accuracy
|
||||
4. **Quality Check**: Run translation validation before merging PRs
|
||||
|
||||
### Why English as Parent Language?
|
||||
|
||||
- **Consistency**: Ensures all languages have the same keys structure
|
||||
- **Reference**: English serves as the source of truth for meaning
|
||||
- **Key management**: Scripts use English as source for key synchronization
|
||||
- **Documentation**: Most technical documentation is in English
|
||||
|
||||
## Best Practices
|
||||
|
||||
### For Developers
|
||||
|
||||
1. **Always use English as reference**: Add new keys to `en-US.json` first - never add keys directly to other languages
|
||||
2. **Use semantic key names**: `dashboard.welcome` instead of `text1`
|
||||
3. **Test key sync**: Run `pnpm run translations:dry-run` before committing
|
||||
4. **Coordinate with translators**: Ensure translation team is aware of new keys
|
||||
5. **Maintain consistency**: Use existing patterns for similar UI elements
|
||||
|
||||
### For Translators
|
||||
|
||||
1. **Focus on [TO_TRANSLATE] strings**: These need immediate attention
|
||||
2. **Check identical strings**: May need localization even if identical to English
|
||||
3. **Use proper formatting**: Maintain HTML tags and placeholders
|
||||
4. **Test in context**: Verify translations work in the actual UI
|
||||
5. **Maintain glossary**: Keep consistent terminology across translations
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Python not found**: Ensure Python 3.6+ is installed and in PATH
|
||||
|
||||
**Permission errors**: Ensure write permissions to message files
|
||||
|
||||
**Encoding issues**: Ensure your terminal supports UTF-8
|
||||
|
||||
### Getting Help
|
||||
|
||||
- Run `pnpm run translations:help` for detailed command examples
|
||||
- Review generated translation reports for specific issues
|
||||
- Check the official documentation for complete reference
|
||||
|
||||
## Output Examples
|
||||
|
||||
### Synchronization Output
|
||||
|
||||
```
|
||||
Loading reference file: en-US.json
|
||||
Reference file contains 980 keys
|
||||
Processing 14 translation files...
|
||||
|
||||
Processing: pt-BR.json
|
||||
🔍 Found 12 missing keys
|
||||
✅ Updated successfully (980/980 keys)
|
||||
|
||||
============================================================
|
||||
SUMMARY
|
||||
============================================================
|
||||
✅ ar-SA.json - 980/980 keys
|
||||
🔄 pt-BR.json - 980/980 keys (+12 added)
|
||||
```
|
||||
|
||||
### Translation Status Report
|
||||
|
||||
```
|
||||
📊 TRANSLATION REPORT
|
||||
Reference: en-US.json (980 strings)
|
||||
================================================================================
|
||||
LANGUAGE COMPLETENESS STRINGS UNTRANSLATED POSSIBLE MATCHES
|
||||
--------------------------------------------------------------------------------
|
||||
✅ pt-BR 100.0% 980/980 0 (0.0%) 5
|
||||
⚠️ fr-FR 100.0% 980/980 12 (2.5%) 3
|
||||
🟡 de-DE 95.2% 962/980 0 (0.0%) 8
|
||||
================================================================================
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
When contributing translations:
|
||||
|
||||
1. **Follow the workflow**: Use the provided scripts for consistency
|
||||
2. **Test thoroughly**: Run complete checks before submitting
|
||||
3. **Document changes**: Note any significant translation decisions
|
||||
4. **Maintain quality**: Ensure manual translations are accurate and appropriate
|
||||
|
||||
The translation management system ensures consistency and makes it easy to maintain high-quality localization across all supported languages.
|
222
apps/docs/content/docs/3.0-beta/uid-gid-configuration.mdx
Normal file
@@ -0,0 +1,222 @@
|
||||
---
|
||||
title: UID/GID Configuration
|
||||
icon: "Users"
|
||||
---
|
||||
|
||||
Configure user and group permissions for seamless bind mount compatibility across different host systems, particularly NAS environments.
|
||||
|
||||
## Overview
|
||||
|
||||
Palmr. supports runtime UID/GID configuration to resolve permission conflicts when using bind mounts. This eliminates the need for manual permission management on your host system.
|
||||
|
||||
**Default Configuration**: UID 1001, GID 1001
|
||||
|
||||
## When to Configure
|
||||
|
||||
UID/GID configuration is recommended when:
|
||||
|
||||
- Using bind mounts with different host user permissions
|
||||
- Deploying on NAS systems (Synology, QNAP, etc.)
|
||||
- Encountering "permission denied" errors
|
||||
- Host system uses different default UID/GID values
|
||||
|
||||
## Environment Variables
|
||||
|
||||
Configure permissions using these optional environment variables:
|
||||
|
||||
| Variable | Description | Default | Example |
|
||||
| ----------- | -------------------------------- | ------- | ------- |
|
||||
| `PALMR_UID` | User ID for container processes | `1001` | `1000` |
|
||||
| `PALMR_GID` | Group ID for container processes | `1001` | `1000` |
|
||||
|
||||
---
|
||||
|
||||
## Finding Host UID/GID
|
||||
|
||||
Determine your host system's user and group IDs:
|
||||
|
||||
```bash
|
||||
# Check current user
|
||||
id
|
||||
|
||||
# Output example
|
||||
uid=1000(user) gid=1000(group) groups=1000(group),27(sudo)
|
||||
```
|
||||
|
||||
Use the `uid` and `gid` values for your configuration.
|
||||
|
||||
---
|
||||
|
||||
## Configuration Examples
|
||||
|
||||
### Standard Linux System
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
image: kyantech/palmr:latest
|
||||
container_name: palmr
|
||||
environment:
|
||||
- ENABLE_S3=false
|
||||
- ENCRYPTION_KEY=your-secure-key-min-32-chars
|
||||
- PALMR_UID=1000
|
||||
- PALMR_GID=1000
|
||||
ports:
|
||||
- "5487:5487"
|
||||
volumes:
|
||||
- ./data:/app/server
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### Synology NAS
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
image: kyantech/palmr:latest
|
||||
container_name: palmr
|
||||
environment:
|
||||
- ENABLE_S3=false
|
||||
- ENCRYPTION_KEY=your-secure-key-min-32-chars
|
||||
- PALMR_UID=1026
|
||||
- PALMR_GID=100
|
||||
ports:
|
||||
- "5487:5487"
|
||||
volumes:
|
||||
- /volume1/docker/palmr:/app/server
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### QNAP NAS
|
||||
|
||||
```yaml
|
||||
services:
|
||||
palmr:
|
||||
image: kyantech/palmr:latest
|
||||
container_name: palmr
|
||||
environment:
|
||||
- ENABLE_S3=false
|
||||
- ENCRYPTION_KEY=your-secure-key-min-32-chars
|
||||
- PALMR_UID=1000
|
||||
- PALMR_GID=100
|
||||
ports:
|
||||
- "5487:5487"
|
||||
volumes:
|
||||
- /share/Container/palmr:/app/server
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Migration Guide
|
||||
|
||||
### Existing Installations
|
||||
|
||||
To add UID/GID configuration to running installations:
|
||||
|
||||
1. **Stop the container**
|
||||
|
||||
```bash
|
||||
docker-compose down
|
||||
```
|
||||
|
||||
2. **Backup your data**
|
||||
|
||||
```bash
|
||||
cp -r ./data ./data-backup
|
||||
```
|
||||
|
||||
3. **Update configuration**
|
||||
Add UID/GID variables to your `docker-compose.yaml`
|
||||
|
||||
4. **Restart with new configuration**
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Verification
|
||||
|
||||
### Check Configuration
|
||||
|
||||
Verify UID/GID settings are applied correctly:
|
||||
|
||||
```bash
|
||||
# View startup logs
|
||||
docker-compose logs palmr | head -20
|
||||
|
||||
# Check file ownership
|
||||
docker exec palmr ls -la /app/server/
|
||||
|
||||
# Verify process UID/GID
|
||||
docker exec palmr ps aux | grep node
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
**Permission issues persist:**
|
||||
|
||||
```bash
|
||||
# Check environment variables
|
||||
docker exec palmr env | grep PALMR
|
||||
|
||||
# Verify file ownership
|
||||
docker exec palmr stat /app/server/prisma/palmr.db
|
||||
|
||||
# Review configuration logs
|
||||
docker-compose logs palmr | grep -E "🔧|🔐|🔽"
|
||||
```
|
||||
|
||||
**NAS-specific debugging:**
|
||||
|
||||
```bash
|
||||
# Synology - Check mount point ownership
|
||||
ls -la /volume1/docker/palmr/
|
||||
|
||||
# QNAP - Check mount point ownership
|
||||
ls -la /share/Container/palmr/
|
||||
|
||||
# Check NAS user configuration
|
||||
cat /etc/passwd | grep -v nobody
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Details
|
||||
|
||||
The UID/GID configuration process:
|
||||
|
||||
1. **Detection** - Environment variables are read during container startup
|
||||
2. **Ownership Update** - File permissions are adjusted to match target UID/GID
|
||||
3. **Privilege Drop** - Application runs with specified user permissions via `su-exec`
|
||||
4. **Logging** - Configuration changes are logged for verification
|
||||
|
||||
This approach provides automatic permission management without user creation or system modification.
|
||||
|
||||
---
|
||||
|
||||
## Build-Time Configuration
|
||||
|
||||
For custom base images with different default values:
|
||||
|
||||
```bash
|
||||
docker build \
|
||||
--build-arg PALMR_UID=2000 \
|
||||
--build-arg PALMR_GID=2000 \
|
||||
-t palmr:custom .
|
||||
```
|
||||
|
||||
Runtime environment variables override build-time defaults.
|
||||
|
||||
---
|
||||
|
||||
## Benefits
|
||||
|
||||
- **Zero Configuration** - Works automatically when environment variables are set
|
||||
- **Universal Compatibility** - Supports any valid UID/GID combination
|
||||
- **NAS Optimized** - Tested with major NAS platforms
|
||||
- **Backward Compatible** - Existing deployments continue without modification
|
||||
- **Performance Optimized** - Lightweight implementation using `su-exec`
|
||||
|
||||
For permission issues with bind mounts, add the appropriate `PALMR_UID` and `PALMR_GID` environment variables to resolve conflicts automatically.
|
@@ -1,3 +1,7 @@
|
||||
{
|
||||
"pages": ["2.0.0-beta", "1.1.7-beta"]
|
||||
"pages": [
|
||||
"3.0-beta",
|
||||
"2.0.0-beta",
|
||||
"1.1.7-beta"
|
||||
]
|
||||
}
|
@@ -1,7 +1,20 @@
|
||||
{
|
||||
"name": "docs-v2",
|
||||
"version": "0.0.0",
|
||||
"name": "palmr-docs",
|
||||
"version": "v3.0-beta",
|
||||
"description": "Docs for Palmr",
|
||||
"private": true,
|
||||
"author": "Daniel Luiz Alves <daniel@kyantech.com.br>",
|
||||
"keywords": [
|
||||
"palmr",
|
||||
"docs",
|
||||
"documentation",
|
||||
"mdx",
|
||||
"nextjs",
|
||||
"react",
|
||||
"typescript"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"packageManager": "pnpm@10.6.0",
|
||||
"scripts": {
|
||||
"build": "next build",
|
||||
"dev": "next dev --turbo",
|
||||
|
BIN
apps/docs/public/assets/v2.1/general/banner.png
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
apps/docs/public/assets/v2.1/general/logo-green.png
Normal file
After Width: | Height: | Size: 7.3 KiB |
BIN
apps/docs/public/assets/v3/architecture/architecture.png
Normal file
After Width: | Height: | Size: 171 KiB |
BIN
apps/docs/public/assets/v3/languages/languages.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
apps/docs/public/assets/v3/oidc/login-flow.png
Normal file
After Width: | Height: | Size: 60 KiB |
BIN
apps/docs/public/assets/v3/oidc/provider-setup.png
Normal file
After Width: | Height: | Size: 115 KiB |
BIN
apps/docs/public/assets/v3/oidc/user-dashboard.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
apps/docs/public/assets/v3/oidc/zitadel-provider-setup.png
Normal file
After Width: | Height: | Size: 263 KiB |
BIN
apps/docs/public/assets/v3/screenshots/dashboard.png
Normal file
After Width: | Height: | Size: 133 KiB |
BIN
apps/docs/public/assets/v3/screenshots/default-reverse.png
Normal file
After Width: | Height: | Size: 97 KiB |
BIN
apps/docs/public/assets/v3/screenshots/files-card.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
apps/docs/public/assets/v3/screenshots/files-list.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
apps/docs/public/assets/v3/screenshots/forgot-password.png
Normal file
After Width: | Height: | Size: 844 KiB |
BIN
apps/docs/public/assets/v3/screenshots/home.png
Normal file
After Width: | Height: | Size: 480 KiB |
BIN
apps/docs/public/assets/v3/screenshots/login.png
Normal file
After Width: | Height: | Size: 822 KiB |
BIN
apps/docs/public/assets/v3/screenshots/profile.png
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
apps/docs/public/assets/v3/screenshots/receive-files.png
Normal file
After Width: | Height: | Size: 106 KiB |
BIN
apps/docs/public/assets/v3/screenshots/settings.png
Normal file
After Width: | Height: | Size: 105 KiB |
BIN
apps/docs/public/assets/v3/screenshots/shares.png
Normal file
After Width: | Height: | Size: 93 KiB |
BIN
apps/docs/public/assets/v3/screenshots/user-management.png
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
apps/docs/public/assets/v3/screenshots/wetransfer.png
Normal file
After Width: | Height: | Size: 3.3 MiB |
BIN
apps/docs/public/assets/v3/smtp/closed-card.png
Normal file
After Width: | Height: | Size: 9.8 KiB |
BIN
apps/docs/public/assets/v3/smtp/dropdown-menu.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
apps/docs/public/assets/v3/smtp/opened-card.png
Normal file
After Width: | Height: | Size: 65 KiB |
BIN
apps/docs/public/assets/v3/smtp/smtp-enabled.png
Normal file
After Width: | Height: | Size: 17 KiB |
@@ -2,15 +2,16 @@ import {
|
||||
type LucideIcon,
|
||||
MousePointer,
|
||||
UploadIcon,
|
||||
Share2Icon,
|
||||
GithubIcon,
|
||||
BookOpenText,
|
||||
CloudIcon,
|
||||
LockIcon,
|
||||
DatabaseIcon,
|
||||
} from "lucide-react";
|
||||
import {
|
||||
BatteryChargingIcon,
|
||||
KeyboardIcon,
|
||||
LayoutIcon,
|
||||
PersonStandingIcon,
|
||||
RocketIcon,
|
||||
SearchIcon,
|
||||
TimerIcon,
|
||||
@@ -58,7 +59,7 @@ const images = [
|
||||
"https://res.cloudinary.com/technical-intelligence/image/upload/v1745546005/Palmr./profile_mizwvg.png",
|
||||
];
|
||||
|
||||
const docsLink = "/docs/2.0.0-beta";
|
||||
const docsLink = "/docs/3.0-beta";
|
||||
|
||||
export default function HomePage() {
|
||||
return (
|
||||
@@ -68,11 +69,8 @@ export default function HomePage() {
|
||||
<Hero />
|
||||
<LogoShowcase />
|
||||
<Feedback />
|
||||
<Introduction />
|
||||
<Architecture />
|
||||
<FileSection />
|
||||
<Highlights />
|
||||
<End />
|
||||
<Features />
|
||||
<GetStarted />
|
||||
</div>
|
||||
</main>
|
||||
<FullWidthFooter />
|
||||
@@ -83,7 +81,12 @@ export default function HomePage() {
|
||||
function Hero() {
|
||||
return (
|
||||
<section className="relative z-[2] flex flex-col border-x border-t px-6 pt-12 pb-10 md:px-12 md:pt-16 max-md:text-center">
|
||||
<h1 className="mb-8 text-5xl font-bold">🌴 Palmr. <span className="text-[10px] font-light text-muted-foreground/50 font-mono">v2.0.0-beta</span></h1>
|
||||
<h1 className="mb-8 text-6xl font-bold">
|
||||
Palmr.{" "}
|
||||
<span className="text-[13px] font-light text-muted-foreground/50 font-mono">
|
||||
v3.0-beta
|
||||
</span>
|
||||
</h1>
|
||||
<h1 className="hidden text-4xl font-medium max-w-[600px] md:block mb-4">
|
||||
Modern & efficient file sharing
|
||||
</h1>
|
||||
@@ -147,123 +150,92 @@ function Feedback() {
|
||||
);
|
||||
}
|
||||
|
||||
export function Introduction() {
|
||||
function Features() {
|
||||
return (
|
||||
<section className="grid grid-cols-1 border-t border-x md:grid-cols-2">
|
||||
<div className="flex flex-col gap-4 border-r p-8 md:p-12">
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-3 rounded-lg">
|
||||
<UploadIcon className="size-6 text-foreground" />
|
||||
<>
|
||||
{/* Core Features */}
|
||||
<section className="grid grid-cols-1 border-t border-x md:grid-cols-2">
|
||||
<div className="flex flex-col gap-4 border-r p-8 md:p-12">
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-3 rounded-lg">
|
||||
<UploadIcon className="size-6 text-foreground" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-semibold">Upload & Share</h3>
|
||||
</div>
|
||||
<h3 className="text-2xl font-semibold">Upload.</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Send your files quickly and safely. Share easily with anyone through
|
||||
secure links.
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-muted-foreground">
|
||||
Send your files quickly and safely.
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-col gap-4 border-r p-8 md:p-12">
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-3 rounded-lg">
|
||||
<Share2Icon className="size-6 text-foreground" />
|
||||
<div className="flex flex-col gap-4 border-r p-8 md:p-12">
|
||||
<div className="flex gap-4 items-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-3 rounded-lg">
|
||||
<LockIcon className="size-6 text-foreground" />
|
||||
</div>
|
||||
<h3 className="text-2xl font-semibold">Secure & Private</h3>
|
||||
</div>
|
||||
<h3 className="text-2xl font-semibold">Share.</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Files are encrypted and protected. You control your data completely.
|
||||
</p>
|
||||
</div>
|
||||
<p className="text-muted-foreground">Easily share with anyone.</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
</section>
|
||||
|
||||
function Architecture() {
|
||||
return (
|
||||
<section className="flex flex-col gap-4 border-x border-t px-8 py-16 md:py-24 lg:flex-row md:px-12">
|
||||
<div className="flex-1 shrink-0 text-start">
|
||||
<p className="mb-4 w-fit bg-fd-primary px-2 py-1 text-md font-bold font-mono text-fd-primary-foreground">
|
||||
Carefully Built
|
||||
</p>
|
||||
<h2 className="mb-4 text-xl font-semibold sm:text-2xl">
|
||||
A complete solution for file sharing.
|
||||
</h2>
|
||||
<p className="mb-6 text-fd-muted-foreground">
|
||||
From the upload to the link generation, everything is designed to be
|
||||
fast, reliable, and privacy-friendly.
|
||||
<br />
|
||||
<br />
|
||||
Every feature was crafted to deliver the best possible experience.
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
{/* Hero Section with Animation */}
|
||||
<section
|
||||
className="relative overflow-hidden border-x border-t px-8 py-16 sm:py-24"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle at center, var(--color-fd-secondary), var(--color-fd-background) 40%)",
|
||||
}}
|
||||
>
|
||||
<div className="text-center">
|
||||
<p className="mb-4 w-fit bg-fd-primary px-3 py-1 text-sm font-bold font-mono text-fd-primary-foreground mx-auto">
|
||||
Open Source & Self-Hosted
|
||||
</p>
|
||||
<h2 className="text-center text-2xl font-semibold sm:text-3xl mb-4">
|
||||
Complete File Sharing Solution
|
||||
</h2>
|
||||
<TypingAnimation className="text-center text-xl text-muted-foreground">
|
||||
Built with Next.js, Fastify, and SQLite
|
||||
</TypingAnimation>
|
||||
</div>
|
||||
<AnimatedGridPattern className="opacity-5" />
|
||||
</section>
|
||||
|
||||
function FileSection() {
|
||||
return (
|
||||
<section
|
||||
className="relative overflow-hidden border-x border-t px-8 py-16 sm:py-24"
|
||||
style={{
|
||||
backgroundImage:
|
||||
"radial-gradient(circle at center, var(--color-fd-secondary), var(--color-fd-background) 40%)",
|
||||
}}
|
||||
>
|
||||
<h2 className="text-center text-2xl font-semibold sm:text-3xl">
|
||||
File Sharing
|
||||
<TypingAnimation className="text-center text-2xl font-semibold sm:text-3xl">
|
||||
Free & Open Source
|
||||
</TypingAnimation>
|
||||
</h2>
|
||||
<AnimatedGridPattern className="opacity-5" />
|
||||
</section>
|
||||
);
|
||||
}
|
||||
{/* Technical Features Grid */}
|
||||
<section className="grid grid-cols-1 border-r md:grid-cols-2 lg:grid-cols-3">
|
||||
<div className="col-span-full flex items-start justify-center border-l border-t p-8 pb-2 text-center">
|
||||
<h2 className="bg-fd-primary px-1 text-2xl font-semibold text-fd-primary-foreground">
|
||||
Key Features
|
||||
</h2>
|
||||
<MousePointer className="-ml-1 mt-8" />
|
||||
</div>
|
||||
|
||||
function Highlights() {
|
||||
const features = [
|
||||
{
|
||||
icon: TimerIcon,
|
||||
title: "Fast & Efficient",
|
||||
text: "Optimized upload and download speeds.",
|
||||
},
|
||||
{
|
||||
icon: LayoutIcon,
|
||||
title: "Intuitive UI",
|
||||
text: "Clean, modern, and easy to use.",
|
||||
},
|
||||
{
|
||||
icon: RocketIcon,
|
||||
title: "Modern Stack",
|
||||
text: "Powered by Next.js, Fastify, MinIO, Postgres and the latest tech.",
|
||||
},
|
||||
{
|
||||
icon: SearchIcon,
|
||||
title: "Smart Search",
|
||||
text: "Find shared files quickly.",
|
||||
},
|
||||
{
|
||||
icon: KeyboardIcon,
|
||||
title: "Open API",
|
||||
text: "REST API endpoinds available for any integrations.",
|
||||
},
|
||||
{
|
||||
icon: PersonStandingIcon,
|
||||
title: "Customizable",
|
||||
text: "Full control over all the system and configurations.",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<section className="grid grid-cols-1 border-r md:grid-cols-2 lg:grid-cols-3">
|
||||
<div className="col-span-full flex items-start justify-center border-l border-t p-8 pb-2 text-center">
|
||||
<h2 className="bg-fd-primary px-1 text-2xl font-semibold text-fd-primary-foreground">
|
||||
Highlights
|
||||
</h2>
|
||||
<MousePointer className="-ml-1 mt-8" />
|
||||
</div>
|
||||
{features.map(({ icon, title, text }, i) => (
|
||||
<Highlight key={i} icon={icon} heading={title}>
|
||||
{text}
|
||||
<Highlight icon={TimerIcon} heading="Lightning Fast">
|
||||
Optimized upload/download speeds with modern architecture
|
||||
</Highlight>
|
||||
))}
|
||||
</section>
|
||||
|
||||
<Highlight icon={CloudIcon} heading="Flexible Storage">
|
||||
Local filesystem or S3-compatible storage options
|
||||
</Highlight>
|
||||
|
||||
<Highlight icon={KeyboardIcon} heading="Developer API">
|
||||
Full REST API with webhooks for seamless integration
|
||||
</Highlight>
|
||||
|
||||
<Highlight icon={SearchIcon} heading="Smart Search">
|
||||
Find and manage your shared files effortlessly
|
||||
</Highlight>
|
||||
|
||||
<Highlight icon={LayoutIcon} heading="Modern UI">
|
||||
Clean, intuitive interface built with best practices
|
||||
</Highlight>
|
||||
|
||||
<Highlight icon={DatabaseIcon} heading="SQLite Powered">
|
||||
Lightweight, reliable database for efficient data handling
|
||||
</Highlight>
|
||||
</section>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -287,70 +259,86 @@ function Highlight({
|
||||
);
|
||||
}
|
||||
|
||||
function End() {
|
||||
function GetStarted() {
|
||||
return (
|
||||
<section className="flex w-full flex-1">
|
||||
<div className="w-full flex flex-col gap-8 overflow-hidden border px-8 py-14">
|
||||
<h2 className="text-3xl font-extrabold font-mono uppercase ">
|
||||
Start Using Now. 🌴
|
||||
</h2>
|
||||
<ul className="mt-2 flex flex-col gap-6">
|
||||
<ListItem icon={TimerIcon} title="Fast Setup">
|
||||
Get up and running in minutes.
|
||||
</ListItem>
|
||||
<ListItem
|
||||
icon={BatteryChargingIcon}
|
||||
title="All under your own control"
|
||||
>
|
||||
Take full control of your file sharing infrastructure.
|
||||
</ListItem>
|
||||
</ul>
|
||||
<div className="flex flex-wrap gap-2 pt-14 pb-0 justify-end">
|
||||
<RippleButton>
|
||||
<div className="flex gap-2 items-center">
|
||||
<BookOpenText size={18} />
|
||||
<Link href={docsLink}>Documentation</Link>
|
||||
<div className="text-center mb-6">
|
||||
<h2 className="text-4xl font-extrabold font-mono uppercase mb-3">
|
||||
Get Started Today
|
||||
</h2>
|
||||
<p className="text-lg text-muted-foreground max-w-2xl mx-auto">
|
||||
Deploy your own secure file sharing platform in minutes. Take
|
||||
control of your data with our self-hosted solution.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-8 mt-8">
|
||||
<div className="text-center space-y-4">
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-4 rounded-full">
|
||||
<TimerIcon className="size-8 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
</RippleButton>
|
||||
<RippleButton>
|
||||
<a
|
||||
href="https://github.com/kyantech/Palmr"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="flex gap-2 items-center"
|
||||
>
|
||||
<GithubIcon size={18} />
|
||||
GitHub
|
||||
</a>
|
||||
</RippleButton>
|
||||
<h3 className="text-xl font-semibold">Quick Setup</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Docker deployment or direct installation - get running in under 5
|
||||
minutes
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="text-center space-y-4">
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-4 rounded-full">
|
||||
<BatteryChargingIcon className="size-8 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold">Full Control</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Self-hosted means you own your data and control every aspect of
|
||||
the platform
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="text-center space-y-4">
|
||||
<div className="flex items-center justify-center">
|
||||
<div className="flex items-center gap-3 text-muted-foreground border border-foreground w-fit p-4 rounded-full">
|
||||
<RocketIcon className="size-8 text-foreground" />
|
||||
</div>
|
||||
</div>
|
||||
<h3 className="text-xl font-semibold">Production Ready</h3>
|
||||
<p className="text-muted-foreground">
|
||||
Latest technologies optimized for performance and security
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="border-t pt-8 mt-12">
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-4">
|
||||
<PulsatingButton>
|
||||
<div className="flex gap-2 items-center">
|
||||
<BookOpenText size={18} />
|
||||
<Link href={docsLink}>Read documentation</Link>
|
||||
</div>
|
||||
</PulsatingButton>
|
||||
<RippleButton>
|
||||
<a
|
||||
href="https://github.com/kyantech/Palmr"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="flex gap-2 items-center"
|
||||
>
|
||||
<GithubIcon size={18} />
|
||||
View on GitHub
|
||||
</a>
|
||||
</RippleButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
function ListItem({
|
||||
icon: Icon,
|
||||
title,
|
||||
children,
|
||||
}: {
|
||||
icon: LucideIcon;
|
||||
title: string;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<li>
|
||||
<span className="flex items-center gap-3 font-medium">
|
||||
<Icon className="size-8" />
|
||||
{title}
|
||||
</span>
|
||||
<span className="mt-2 block text-sm text-fd-muted-foreground">
|
||||
{children}
|
||||
</span>
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function FullWidthFooter() {
|
||||
return (
|
||||
<footer className="w-full flex items-center justify-center p-6 border-t font-light container max-w-7xl">
|
||||
|
19
apps/docs/src/app/api/generate-key/route.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { execSync } from "child_process";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const key = execSync(
|
||||
"openssl rand -base64 48 | tr -dc 'A-Za-z0-9' | head -c 64"
|
||||
)
|
||||
.toString()
|
||||
.trim();
|
||||
return NextResponse.json({ key });
|
||||
} catch (error) {
|
||||
console.error("Failed to generate key:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to generate key" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
import { source } from '@/lib/source';
|
||||
import { createFromSource } from 'fumadocs-core/search/server';
|
||||
|
||||
import { source } from "@/lib/source";
|
||||
import { createFromSource } from "fumadocs-core/search/server";
|
||||
|
||||
export const { GET } = createFromSource(source, (page) => {
|
||||
return {
|
||||
title: page.data.title,
|
||||
@@ -8,6 +8,10 @@ export const { GET } = createFromSource(source, (page) => {
|
||||
url: page.url,
|
||||
id: page.url,
|
||||
structuredData: page.data.structuredData,
|
||||
tag: page.url.startsWith('/docs/2.0.0-beta') ? 'v2.0.0-beta' : 'v1.1.7-beta'
|
||||
tag: page.url.startsWith("/docs/3.0-beta")
|
||||
? "v3.0-beta"
|
||||
: page.url.startsWith("/docs/2.0.0-beta")
|
||||
? "v2.0.0-beta"
|
||||
: "v1.1.7-beta",
|
||||
};
|
||||
});
|
||||
|
@@ -10,6 +10,7 @@ import { createRelativeLink } from "fumadocs-ui/mdx";
|
||||
import { getMDXComponents } from "@/mdx-components";
|
||||
import { Footer } from "../components/footer";
|
||||
import { Sponsor } from "../components/sponsor";
|
||||
import { VersionWarning } from "@/components/version-warning";
|
||||
|
||||
export default async function Page(props: {
|
||||
params: Promise<{ slug?: string[] }>;
|
||||
@@ -20,16 +21,22 @@ export default async function Page(props: {
|
||||
|
||||
const MDXContent = page.data.body;
|
||||
|
||||
// Check if this is an older version page that needs a warning
|
||||
const shouldShowWarning =
|
||||
page.url.startsWith("/docs/2.0.0-beta") ||
|
||||
page.url.startsWith("/docs/1.1.7-beta");
|
||||
|
||||
return (
|
||||
<DocsPage
|
||||
toc={page.data.toc}
|
||||
full={page.data.full}
|
||||
footer={{ enabled: true, component: <Footer /> }}
|
||||
tableOfContent={{
|
||||
style: "clerk",
|
||||
footer: <Sponsor/>
|
||||
tableOfContent={{
|
||||
style: "clerk",
|
||||
footer: <Sponsor />,
|
||||
}}
|
||||
>
|
||||
{shouldShowWarning && <VersionWarning />}
|
||||
<DocsTitle>{page.data.title}</DocsTitle>
|
||||
<div className="border w-full"></div>
|
||||
<DocsDescription>{page.data.description}</DocsDescription>
|
||||
@@ -56,7 +63,7 @@ export async function generateMetadata(props: {
|
||||
if (!page) notFound();
|
||||
|
||||
return {
|
||||
title: page.data.title + " | 🌴 Palmr. Docs",
|
||||
title: page.data.title + " | Palmr. Docs",
|
||||
description: page.data.description,
|
||||
};
|
||||
}
|
||||
|
@@ -7,7 +7,7 @@ export function Sponsor() {
|
||||
href="https://github.com/sponsors/kyantech"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="m-2 mt-5 flex items-center justify-center gap-2 p-3 rounded-lg border-2 bg-card text-card-foreground hover:bg-accent/50 transition-colors hover:bg-black/10"
|
||||
className="m-2 mt-5 flex items-center justify-center gap-2 p-3 rounded-lg border-2 bg-card text-card-foreground hover:bg-accent/50 transition-colors "
|
||||
>
|
||||
<Coffee size={18} />
|
||||
<span className="text-xs font-medium">Sponsor on GitHub</span>
|
||||
|
@@ -1,11 +1,16 @@
|
||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||
import type { ReactNode } from 'react';
|
||||
import { baseOptions } from '@/app/layout.config';
|
||||
import { source } from '@/lib/source';
|
||||
import { DocsLayout } from "fumadocs-ui/layouts/docs";
|
||||
import type { ReactNode } from "react";
|
||||
import { baseOptions } from "@/app/layout.config";
|
||||
import { source } from "@/lib/source";
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<DocsLayout tree={source.pageTree} {...baseOptions} githubUrl='https://github.com/kyantech/Palmr' links={[]}>
|
||||
<DocsLayout
|
||||
tree={source.pageTree}
|
||||
{...baseOptions}
|
||||
githubUrl="https://github.com/kyantech/Palmr"
|
||||
links={[]}
|
||||
>
|
||||
{children}
|
||||
</DocsLayout>
|
||||
);
|
||||
|
@@ -4,7 +4,6 @@
|
||||
@import "tw-animate-css";
|
||||
|
||||
@custom-variant dark (&:is(.dark *));
|
||||
/* @import 'fumadocs-ui/css/black.css'; */
|
||||
|
||||
@source '../../node_modules/fumadocs-ui/dist/**/*.js';
|
||||
|
||||
|
@@ -1,25 +1,31 @@
|
||||
import { LATEST_VERSION_PATH } from "@/config/constants";
|
||||
import type { BaseLayoutProps } from "fumadocs-ui/layouts/shared";
|
||||
import { Github } from "lucide-react";
|
||||
import { Github, Palmtree } from "lucide-react";
|
||||
|
||||
export const baseOptions: BaseLayoutProps = {
|
||||
nav: {
|
||||
title: "🌴 Palmr.",
|
||||
title: (
|
||||
<div className="flex items-start gap-1.5">
|
||||
<Palmtree className="text-[#52822D]" />
|
||||
<span className="text-xl font-medium">Palmr.</span>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
links: [
|
||||
{
|
||||
text: "Docs",
|
||||
url: "/docs/2.0.0-beta",
|
||||
url: LATEST_VERSION_PATH,
|
||||
active: "nested-url",
|
||||
},
|
||||
{
|
||||
text: "Github",
|
||||
url: "https://github.com/kyantech/Palmr",
|
||||
active: "nested-url",
|
||||
icon: (
|
||||
<>
|
||||
<Github fill="currentColor" />
|
||||
</>
|
||||
),
|
||||
}
|
||||
],
|
||||
{
|
||||
text: "Github",
|
||||
url: "https://github.com/kyantech/Palmr",
|
||||
active: "nested-url",
|
||||
icon: (
|
||||
<>
|
||||
<Github fill="currentColor" />
|
||||
</>
|
||||
),
|
||||
},
|
||||
],
|
||||
};
|
||||
|
@@ -4,35 +4,43 @@ import { RootProvider } from "fumadocs-ui/provider";
|
||||
import { Inter } from "next/font/google";
|
||||
import type { ReactNode } from "react";
|
||||
import Link from "fumadocs-core/link";
|
||||
import { LATEST_VERSION, LATEST_VERSION_PATH } from "@/config/constants";
|
||||
|
||||
const inter = Inter({
|
||||
subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata = {
|
||||
title: "🌴 Palmr. | Official Website",
|
||||
description: "Palmr. is a fast, simple and powerful document sharing platform.",
|
||||
title: "Palmr. | Official Website",
|
||||
description:
|
||||
"Palmr. is a fast, simple and powerful document sharing platform.",
|
||||
};
|
||||
|
||||
export default function Layout({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<html lang="en" className={inter.className} suppressHydrationWarning>
|
||||
<body className="flex flex-col min-h-screen">
|
||||
<Banner variant="rainbow" id="banner-v-2">
|
||||
<Link href="/docs/2.0.0-beta">Palmr. v2.0.0-beta has released!</Link>
|
||||
<Banner variant="rainbow" id="banner-21-beta">
|
||||
<Link href={LATEST_VERSION_PATH}>
|
||||
Palmr. {LATEST_VERSION} has released!
|
||||
</Link>
|
||||
</Banner>
|
||||
<RootProvider
|
||||
search={{
|
||||
options: {
|
||||
defaultTag: "2.0.0-beta",
|
||||
defaultTag: "3.0-beta",
|
||||
tags: [
|
||||
{
|
||||
name: "v1.1.7 Beta",
|
||||
value: "1.1.7-beta",
|
||||
},
|
||||
{
|
||||
name: "v2.0.0 Beta ✨",
|
||||
name: "v2.0.0 Beta",
|
||||
value: "2.0.0-beta",
|
||||
},
|
||||
{
|
||||
name: "v3.0 Beta ✨",
|
||||
value: "3.0-beta",
|
||||
props: {
|
||||
style: {
|
||||
border: "1px solid rgba(0,165,80,0.2)",
|
||||
|
89
apps/docs/src/components/KeyGenerator.tsx
Normal file
@@ -0,0 +1,89 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { Copy, X } from "lucide-react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Toast } from "@/components/ui/toast";
|
||||
|
||||
export function KeyGenerator() {
|
||||
const [key, setKey] = useState("");
|
||||
const [showToast, setShowToast] = useState(false);
|
||||
|
||||
const generateKey = async () => {
|
||||
try {
|
||||
const response = await fetch("/api/generate-key");
|
||||
const data = await response.json();
|
||||
setKey(data.key);
|
||||
} catch (error) {
|
||||
console.error("Failed to generate key:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const copyToClipboard = async () => {
|
||||
if (key) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(key);
|
||||
setShowToast(true);
|
||||
} catch (error) {
|
||||
console.error("Failed to copy:", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="my-4 space-y-4">
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={generateKey}>Generate new key</Button>
|
||||
{key && (
|
||||
<Button
|
||||
onClick={() => setKey("")}
|
||||
className="!border-red-200 !text-red-600 hover:!bg-red-50 dark:!border-red-800/50 dark:!text-red-400 dark:hover:!bg-red-950/50"
|
||||
>
|
||||
<X className="h-4 w-4 mr-1" />
|
||||
Clear
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="relative">
|
||||
<code className="block w-full p-3 bg-gray-100 dark:bg-black/80 rounded-md font-mono text-sm min-h-[2.5rem] border border-gray-200 dark:border-gray-700">
|
||||
{key ? (
|
||||
<>
|
||||
<span className="select-none text-gray-500 dark:text-gray-400">
|
||||
ENCRYPTION_KEY=
|
||||
</span>
|
||||
<span className="text-green-900 dark:text-green-600">{key}</span>
|
||||
</>
|
||||
) : (
|
||||
<span className="text-gray-500 dark:text-gray-400">
|
||||
Click the button above to generate a new encryption key
|
||||
</span>
|
||||
)}
|
||||
</code>
|
||||
{key && (
|
||||
<button
|
||||
onClick={copyToClipboard}
|
||||
className="absolute right-2 top-1/2 -translate-y-1/2 p-1.5 rounded-md hover:bg-gray-200 dark:hover:bg-gray-700 transition-colors cursor-pointer"
|
||||
title="Copy to clipboard"
|
||||
>
|
||||
<Copy className="h-4 w-4 text-gray-600 dark:text-gray-400" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{key && (
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Copy the key and paste it into your <code>docker-compose.yml</code>{" "}
|
||||
file.
|
||||
</p>
|
||||
)}
|
||||
|
||||
{showToast && (
|
||||
<Toast
|
||||
message="Key copied to clipboard!"
|
||||
onClose={() => setShowToast(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
34
apps/docs/src/components/ui/button.tsx
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ButtonHTMLAttributes, forwardRef } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, children, ...props }, ref) => {
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center rounded-md px-4 py-2",
|
||||
"text-base font-medium transition-all duration-200 cursor-pointer",
|
||||
"text-gray-700 dark:text-gray-200",
|
||||
"border border-gray-300 dark:border-gray-600",
|
||||
"hover:border-gray-400 dark:hover:border-gray-500",
|
||||
"hover:bg-gray-50 dark:hover:bg-gray-800/50",
|
||||
"hover:shadow-sm",
|
||||
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-gray-400",
|
||||
"dark:focus-visible:ring-gray-500 focus-visible:ring-offset-2",
|
||||
"disabled:pointer-events-none disabled:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Button.displayName = "Button";
|
31
apps/docs/src/components/ui/toast.tsx
Normal file
@@ -0,0 +1,31 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect } from "react";
|
||||
import { createPortal } from "react-dom";
|
||||
import { CheckCircle } from "lucide-react";
|
||||
|
||||
interface ToastProps {
|
||||
message: string;
|
||||
duration?: number;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export function Toast({ message, duration = 2000, onClose }: ToastProps) {
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
onClose();
|
||||
}, duration);
|
||||
|
||||
return () => clearTimeout(timer);
|
||||
}, [duration, onClose]);
|
||||
|
||||
return createPortal(
|
||||
<div className="fixed bottom-4 right-4 z-50 animate-in fade-in slide-in-from-bottom-4">
|
||||
<div className="flex items-center gap-2 bg-white dark:bg-black/80 text-black dark:text-white px-4 py-2 rounded-md shadow-lg border border-gray-200 dark:border-gray-700">
|
||||
<CheckCircle className="h-5 w-5 text-green-400" />
|
||||
<p className="text-sm font-medium">{message}</p>
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
}
|
95
apps/docs/src/components/ui/zoomable-image.tsx
Normal file
@@ -0,0 +1,95 @@
|
||||
"use client";
|
||||
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { X, ZoomIn } from "lucide-react";
|
||||
|
||||
interface ZoomableImageProps {
|
||||
src: string;
|
||||
alt: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export const ZoomableImage: React.FC<ZoomableImageProps> = ({
|
||||
src,
|
||||
alt,
|
||||
className,
|
||||
}) => {
|
||||
const [isZoomed, setIsZoomed] = useState(false);
|
||||
|
||||
const handleImageClick = () => {
|
||||
setIsZoomed(true);
|
||||
};
|
||||
|
||||
const handleCloseZoom = () => {
|
||||
setIsZoomed(false);
|
||||
};
|
||||
|
||||
const handleBackdropClick = (e: React.MouseEvent) => {
|
||||
if (e.target === e.currentTarget) {
|
||||
setIsZoomed(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Handle ESC key press
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (event: KeyboardEvent) => {
|
||||
if (event.key === "Escape" && isZoomed) {
|
||||
setIsZoomed(false);
|
||||
}
|
||||
};
|
||||
|
||||
if (isZoomed) {
|
||||
document.addEventListener("keydown", handleKeyDown);
|
||||
}
|
||||
|
||||
return () => {
|
||||
document.removeEventListener("keydown", handleKeyDown);
|
||||
};
|
||||
}, [isZoomed]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Thumbnail Image */}
|
||||
<div className="relative group cursor-pointer" onClick={handleImageClick}>
|
||||
<img
|
||||
src={src}
|
||||
alt={alt}
|
||||
className={cn(
|
||||
"w-full h-auto rounded-lg border border-gray-200 dark:border-gray-700 shadow-sm transition-all duration-300 hover:shadow-md hover:border-gray-300 dark:hover:border-gray-600",
|
||||
className
|
||||
)}
|
||||
/>
|
||||
{/* Zoom Icon Overlay */}
|
||||
<div className="absolute inset-0 bg-black/0 group-hover:bg-black/10 transition-all duration-300 rounded-lg flex items-center justify-center">
|
||||
<ZoomIn className="w-8 h-8 text-white opacity-0 group-hover:opacity-100 transition-opacity duration-300 drop-shadow-lg" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Zoomed Modal */}
|
||||
{isZoomed && (
|
||||
<div
|
||||
className="fixed inset-0 z-50 bg-black/80 backdrop-blur-sm flex items-center justify-center p-4"
|
||||
onClick={handleBackdropClick}
|
||||
>
|
||||
{/* Close Button */}
|
||||
<button
|
||||
onClick={handleCloseZoom}
|
||||
className="absolute top-4 right-4 z-10 p-2 bg-white/10 hover:bg-white/20 rounded-full transition-colors duration-200"
|
||||
aria-label="Close zoom"
|
||||
>
|
||||
<X className="w-6 h-6 text-white" />
|
||||
</button>
|
||||
|
||||
{/* Zoomed Image */}
|
||||
<img
|
||||
src={src}
|
||||
alt={alt}
|
||||
className="max-w-[90vw] max-h-[90vh] w-auto h-auto object-contain rounded-lg border border-gray-300 dark:border-gray-600 shadow-2xl"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
137
apps/docs/src/components/version-warning.tsx
Normal file
@@ -0,0 +1,137 @@
|
||||
"use client";
|
||||
|
||||
import { LATEST_VERSION, LATEST_VERSION_PATH } from "@/config/constants";
|
||||
import { AlertTriangle, ArrowRightIcon, X } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
|
||||
function useIntersectionObserver(
|
||||
targetRef: React.RefObject<HTMLDivElement | null>
|
||||
) {
|
||||
const [isIntersecting, setIsIntersecting] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
([entry]) => setIsIntersecting(entry.isIntersecting),
|
||||
{ threshold: 0, rootMargin: "-10px 0px 0px 0px" }
|
||||
);
|
||||
|
||||
if (targetRef.current) {
|
||||
observer.observe(targetRef.current);
|
||||
}
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, [targetRef]);
|
||||
|
||||
return isIntersecting;
|
||||
}
|
||||
|
||||
function useClickOutside(
|
||||
ref: React.RefObject<HTMLDivElement | null>,
|
||||
callback: () => void
|
||||
) {
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (ref.current && !ref.current.contains(event.target as Node)) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => document.removeEventListener("mousedown", handleClickOutside);
|
||||
}, [ref, callback]);
|
||||
}
|
||||
|
||||
function WarningContent({ onClose }: { onClose: () => void }) {
|
||||
return (
|
||||
<>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="absolute top-3 right-3 text-amber-600 dark:text-amber-400 hover:text-amber-800 dark:hover:text-amber-200 transition-colors cursor-pointer"
|
||||
aria-label="Close warning"
|
||||
>
|
||||
<X className="h-5 w-5" />
|
||||
</button>
|
||||
<div className="flex items-start pr-8">
|
||||
<AlertTriangle className="h-8 w-8 text-amber-500 dark:text-amber-400 mt-0.5 mr-3 flex-shrink-0" />
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-medium text-amber-800 dark:text-amber-100 mb-2">
|
||||
Deprecated version documentation
|
||||
</h3>
|
||||
<p className="text-[15px] text-amber-700 dark:text-amber-300 mb-3">
|
||||
This documentation refers to a previous version of Palmr. It may
|
||||
contain more complex configurations and bugs that have already been
|
||||
fixed.
|
||||
</p>
|
||||
<Link
|
||||
href={LATEST_VERSION_PATH}
|
||||
className="inline-flex items-center text-base font-medium text-amber-800 dark:text-amber-100 hover:text-amber-900 dark:hover:text-amber-200"
|
||||
>
|
||||
View latest documentation ({LATEST_VERSION}){" "}
|
||||
<ArrowRightIcon className="w-4 h-4 ml-1 mt-0.5" />
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function FloatingWarning({ onClose }: { onClose: () => void }) {
|
||||
const [showContent, setShowContent] = useState(false);
|
||||
const floatingRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useClickOutside(floatingRef, () => setShowContent(false));
|
||||
|
||||
const toggleContent = () => setShowContent(!showContent);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed bottom-6 z-50"
|
||||
style={{ right: "max(1.5rem, calc((100vw - 1024px) / 2 + 1.5rem))" }}
|
||||
>
|
||||
<div className="relative" ref={floatingRef}>
|
||||
<button
|
||||
onClick={toggleContent}
|
||||
className="w-12 h-12 bg-amber-500 dark:bg-amber-600 rounded-full flex items-center justify-center shadow-2xl hover:bg-amber-600 dark:hover:bg-amber-700 transition-all duration-200 cursor-pointer ring-2 ring-amber-300 dark:ring-amber-500 hover:ring-4 hover:ring-amber-400 dark:hover:ring-amber-400"
|
||||
aria-label="Toggle deprecated version warning"
|
||||
>
|
||||
<AlertTriangle className="h-6 w-6 text-white drop-shadow-sm" />
|
||||
</button>
|
||||
|
||||
{showContent && (
|
||||
<div className="absolute bottom-full right-0 mb-2 transition-all duration-200">
|
||||
<div className="p-4 bg-amber-50 dark:bg-amber-900 rounded-md border-2 border-amber-300 dark:border-amber-600 shadow-2xl ring-1 ring-amber-200 dark:ring-amber-700 w-[600px] max-w-[calc(100vw-8rem)] relative">
|
||||
<WarningContent onClose={onClose} />
|
||||
<div className="absolute top-full right-4 w-0 h-0 border-l-4 border-r-4 border-t-4 border-l-transparent border-r-transparent border-t-amber-300 dark:border-t-amber-600"></div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function VersionWarning() {
|
||||
const [isVisible, setIsVisible] = useState(true);
|
||||
const warningRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isIntersecting = useIntersectionObserver(warningRef);
|
||||
const shouldShowFloating = isVisible && !isIntersecting;
|
||||
|
||||
const handleClose = () => setIsVisible(false);
|
||||
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div
|
||||
ref={warningRef}
|
||||
className="mb-6 p-4 bg-amber-50 dark:bg-amber-900/20 rounded-md relative border border-amber-200 dark:border-amber-800"
|
||||
>
|
||||
<WarningContent onClose={handleClose} />
|
||||
</div>
|
||||
|
||||
{shouldShowFloating && <FloatingWarning onClose={handleClose} />}
|
||||
</div>
|
||||
);
|
||||
}
|
2
apps/docs/src/config/constants.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export const LATEST_VERSION_PATH = "/docs/3.0-beta";
|
||||
export const LATEST_VERSION = "v3.0-beta";
|
@@ -1,9 +1,16 @@
|
||||
import { docs } from '@/.source';
|
||||
import { loader } from 'fumadocs-core/source';
|
||||
import { docs } from "@/.source";
|
||||
import { loader } from "fumadocs-core/source";
|
||||
import { icons } from "lucide-react";
|
||||
import { createElement } from "react";
|
||||
|
||||
// See https://fumadocs.vercel.app/docs/headless/source-api for more info
|
||||
export const source = loader({
|
||||
// it assigns a URL to your pages
|
||||
baseUrl: '/docs',
|
||||
baseUrl: "/docs",
|
||||
source: docs.toFumadocsSource(),
|
||||
icon(icon) {
|
||||
if (icon && icon in icons) {
|
||||
return createElement(icons[icon as keyof typeof icons]);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import { clsx, type ClassValue } from "clsx"
|
||||
import { twMerge } from "tailwind-merge"
|
||||
import { type ClassValue, clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs))
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
|
@@ -1,10 +1,12 @@
|
||||
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||
import type { MDXComponents } from 'mdx/types';
|
||||
import defaultMdxComponents from "fumadocs-ui/mdx";
|
||||
import type { MDXComponents } from "mdx/types";
|
||||
import { KeyGenerator } from "@/components/KeyGenerator";
|
||||
|
||||
// use this function to get MDX components, you will need it for rendering MDX
|
||||
export function getMDXComponents(components?: MDXComponents): MDXComponents {
|
||||
return {
|
||||
...defaultMdxComponents,
|
||||
KeyGenerator,
|
||||
...components,
|
||||
};
|
||||
}
|
||||
|
@@ -1,9 +0,0 @@
|
||||
node_modules
|
||||
dist
|
||||
.env
|
||||
.env.*
|
||||
*.log
|
||||
.git
|
||||
.gitignore
|
||||
.next
|
||||
.cache
|
@@ -1,13 +1,15 @@
|
||||
DATABASE_URL="postgresql://palmr:palmr123@localhost:5432/palmr?schema=public"
|
||||
# FOR FILESYSTEM STORAGE ENV VARS
|
||||
ENABLE_S3=false
|
||||
ENCRYPTION_KEY=change-this-key-in-production-min-32-chars
|
||||
DATABASE_URL="file:./palmr.db"
|
||||
|
||||
FRONTEND_URL="http://localhost:3000"
|
||||
MINIO_ENDPOINT="localhost"
|
||||
MINIO_PORT="9000"
|
||||
MINIO_USE_SSL="false"
|
||||
MINIO_ROOT_USER="palmr"
|
||||
MINIO_ROOT_PASSWORD="palmr123"
|
||||
MINIO_REGION="sa-east-1"
|
||||
MINIO_BUCKET_NAME="files"
|
||||
PORT=3333
|
||||
SERVER_IP="localhost"
|
||||
MAX_FILESIZE="1073741824"
|
||||
# FOR USE WITH S3 COMPATIBLE STORAGE
|
||||
# ENABLE_S3=true
|
||||
# S3_ENDPOINT=
|
||||
# S3_PORT=
|
||||
# S3_USE_SSL=
|
||||
# S3_ACCESS_KEY=
|
||||
# S3_SECRET_KEY=
|
||||
# S3_REGION=
|
||||
# S3_BUCKET_NAME=
|
||||
# S3_FORCE_PATH_STYLE=
|
||||
|
3
apps/server/.gitignore
vendored
@@ -1,3 +1,6 @@
|
||||
node_modules
|
||||
.env
|
||||
dist/*
|
||||
uploads/*
|
||||
temp-chunks/*
|
||||
prisma/*.db
|
||||
|
@@ -1,26 +0,0 @@
|
||||
FROM node:22-alpine
|
||||
|
||||
WORKDIR /app/server
|
||||
|
||||
RUN apk add --no-cache netcat-openbsd
|
||||
RUN npm install -g pnpm
|
||||
|
||||
COPY package*.json ./
|
||||
COPY pnpm-lock.yaml ./
|
||||
COPY prisma ./prisma/
|
||||
COPY scripts ./scripts/
|
||||
|
||||
RUN rm -rf node_modules/.prisma
|
||||
|
||||
RUN pnpm install --frozen-lockfile
|
||||
|
||||
RUN npx prisma generate
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN pnpm build
|
||||
RUN chmod +x ./scripts/start.sh
|
||||
|
||||
EXPOSE 3333
|
||||
|
||||
CMD ["./scripts/start.sh"]
|
@@ -1,58 +0,0 @@
|
||||
services:
|
||||
|
||||
minio:
|
||||
image: minio/minio:latest
|
||||
container_name: minio
|
||||
ports:
|
||||
- "9000:9000"
|
||||
- "9001:9001"
|
||||
environment:
|
||||
- MINIO_ROOT_USER=palmr
|
||||
- MINIO_ROOT_PASSWORD=palmr123
|
||||
volumes:
|
||||
- minio_data:/data
|
||||
command: server /data --console-address ":9001"
|
||||
restart: "unless-stopped"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/ready"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
minio-init:
|
||||
image: minio/mc:latest
|
||||
container_name: minio-init
|
||||
depends_on:
|
||||
minio:
|
||||
condition: service_healthy
|
||||
entrypoint: >
|
||||
sh -c "
|
||||
mc alias set myminio http://minio:9000 palmr palmr123 &&
|
||||
mc mb myminio/files --ignore-existing
|
||||
"
|
||||
restart: "no"
|
||||
environment:
|
||||
MINIO_ROOT_USER: palmr
|
||||
MINIO_ROOT_PASSWORD: palmr123
|
||||
|
||||
postgres:
|
||||
image: bitnami/postgresql:17.2.0
|
||||
container_name: palmr-postgres
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRESQL_USERNAME=palmr
|
||||
- POSTGRESQL_PASSWORD=palmr123
|
||||
- POSTGRESQL_DATABASE=palmr
|
||||
volumes:
|
||||
- postgres_data:/bitnami/postgresql
|
||||
restart: "unless-stopped"
|
||||
healthcheck:
|
||||
test: ["CMD", "pg_isready", "-U", "palmr"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
minio_data:
|
@@ -1,7 +1,19 @@
|
||||
{
|
||||
"name": "palmr-api",
|
||||
"version": "1.1.6",
|
||||
"description": "",
|
||||
"version": "3.0-beta",
|
||||
"description": "API for Palmr",
|
||||
"private": true,
|
||||
"author": "Daniel Luiz Alves <daniel@kyantech.com.br>",
|
||||
"keywords": [
|
||||
"palmr",
|
||||
"api",
|
||||
"backend",
|
||||
"server",
|
||||
"nodejs",
|
||||
"typescript"
|
||||
],
|
||||
"license": "BSD-2-Clause",
|
||||
"packageManager": "pnpm@10.6.0",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"dev": "tsx watch src/server.ts",
|
||||
@@ -11,12 +23,14 @@
|
||||
"lint:fix": "eslint \"src/**/*.{js,jsx,ts,tsx}\" --fix",
|
||||
"format": "prettier . --write",
|
||||
"format:check": "prettier . --check",
|
||||
"db:seed": "ts-node prisma/seed.ts"
|
||||
"db:seed": "ts-node prisma/seed.js"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "node prisma/seed.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.817.0",
|
||||
"@aws-sdk/s3-request-presigner": "^3.817.0",
|
||||
"@fastify/cookie": "^11.0.2",
|
||||
"@fastify/cors": "^10.0.2",
|
||||
"@fastify/jwt": "^9.0.3",
|
||||
@@ -26,11 +40,15 @@
|
||||
"@fastify/swagger-ui": "^5.2.1",
|
||||
"@prisma/client": "^6.4.1",
|
||||
"@scalar/fastify-api-reference": "^1.25.116",
|
||||
"@types/crypto-js": "^4.2.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"crypto-js": "^4.2.0",
|
||||
"fastify": "^5.2.1",
|
||||
"fastify-type-provider-zod": "^4.0.2",
|
||||
"minio": "^8.0.4",
|
||||
"jose": "^5.10.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"nodemailer": "^6.10.0",
|
||||
"openid-client": "^6.5.0",
|
||||
"sharp": "^0.33.5",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
|
1489
apps/server/pnpm-lock.yaml
generated
@@ -1,178 +0,0 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "users" (
|
||||
"id" TEXT NOT NULL,
|
||||
"firstName" TEXT NOT NULL,
|
||||
"lastName" TEXT NOT NULL,
|
||||
"username" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"image" TEXT,
|
||||
"isAdmin" BOOLEAN NOT NULL DEFAULT false,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "files" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"extension" TEXT NOT NULL,
|
||||
"size" BIGINT NOT NULL,
|
||||
"objectName" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "files_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "shares" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT,
|
||||
"views" INTEGER NOT NULL DEFAULT 0,
|
||||
"expiration" TIMESTAMP(3),
|
||||
"description" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"creatorId" TEXT,
|
||||
"securityId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "shares_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "share_security" (
|
||||
"id" TEXT NOT NULL,
|
||||
"password" TEXT,
|
||||
"maxViews" INTEGER,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "share_security_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "share_recipients" (
|
||||
"id" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"shareId" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "share_recipients_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "app_configs" (
|
||||
"id" TEXT NOT NULL,
|
||||
"key" TEXT NOT NULL,
|
||||
"value" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"group" TEXT NOT NULL,
|
||||
"isSystem" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "app_configs_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "login_attempts" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"attempts" INTEGER NOT NULL DEFAULT 1,
|
||||
"lastAttempt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "login_attempts_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "password_resets" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"token" TEXT NOT NULL,
|
||||
"expiresAt" TIMESTAMP(3) NOT NULL,
|
||||
"used" BOOLEAN NOT NULL DEFAULT false,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "password_resets_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "share_aliases" (
|
||||
"id" TEXT NOT NULL,
|
||||
"alias" TEXT NOT NULL,
|
||||
"shareId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "share_aliases_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "_ShareFiles" (
|
||||
"A" TEXT NOT NULL,
|
||||
"B" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "_ShareFiles_AB_pkey" PRIMARY KEY ("A","B")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_username_key" ON "users"("username");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "shares_securityId_key" ON "shares"("securityId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "app_configs_key_key" ON "app_configs"("key");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "login_attempts_userId_key" ON "login_attempts"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "password_resets_token_key" ON "password_resets"("token");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "share_aliases_alias_key" ON "share_aliases"("alias");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "share_aliases_shareId_key" ON "share_aliases"("shareId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "_ShareFiles_B_index" ON "_ShareFiles"("B");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "files" ADD CONSTRAINT "files_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "shares" ADD CONSTRAINT "shares_creatorId_fkey" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "shares" ADD CONSTRAINT "shares_securityId_fkey" FOREIGN KEY ("securityId") REFERENCES "share_security"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "share_recipients" ADD CONSTRAINT "share_recipients_shareId_fkey" FOREIGN KEY ("shareId") REFERENCES "shares"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "login_attempts" ADD CONSTRAINT "login_attempts_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "password_resets" ADD CONSTRAINT "password_resets_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "share_aliases" ADD CONSTRAINT "share_aliases_shareId_fkey" FOREIGN KEY ("shareId") REFERENCES "shares"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ShareFiles" ADD CONSTRAINT "_ShareFiles_A_fkey" FOREIGN KEY ("A") REFERENCES "files"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "_ShareFiles" ADD CONSTRAINT "_ShareFiles_B_fkey" FOREIGN KEY ("B") REFERENCES "shares"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
@@ -1,3 +0,0 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
@@ -3,7 +3,7 @@ generator client {
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
provider = "sqlite"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
@@ -13,19 +13,21 @@ model User {
|
||||
lastName String
|
||||
username String @unique
|
||||
email String @unique
|
||||
password String
|
||||
password String?
|
||||
image String?
|
||||
isAdmin Boolean @default(false)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
files File[]
|
||||
shares Share[]
|
||||
files File[]
|
||||
shares Share[]
|
||||
reverseShares ReverseShare[]
|
||||
|
||||
loginAttempts LoginAttempt?
|
||||
|
||||
passwordResets PasswordReset[]
|
||||
authProviders UserAuthProvider[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
@@ -143,3 +145,82 @@ model ShareAlias {
|
||||
|
||||
@@map("share_aliases")
|
||||
}
|
||||
|
||||
model UserAuthProvider {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
provider String
|
||||
providerId String?
|
||||
metadata String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([userId, provider])
|
||||
@@map("user_auth_providers")
|
||||
}
|
||||
|
||||
model ReverseShare {
|
||||
id String @id @default(cuid())
|
||||
name String?
|
||||
description String?
|
||||
expiration DateTime?
|
||||
maxFiles Int?
|
||||
maxFileSize BigInt?
|
||||
allowedFileTypes String?
|
||||
password String?
|
||||
pageLayout PageLayout @default(DEFAULT)
|
||||
isActive Boolean @default(true)
|
||||
nameFieldRequired FieldRequirement @default(OPTIONAL)
|
||||
emailFieldRequired FieldRequirement @default(OPTIONAL)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
creatorId String
|
||||
creator User @relation(fields: [creatorId], references: [id], onDelete: Cascade)
|
||||
|
||||
files ReverseShareFile[]
|
||||
alias ReverseShareAlias?
|
||||
|
||||
@@map("reverse_shares")
|
||||
}
|
||||
|
||||
model ReverseShareFile {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
description String?
|
||||
extension String
|
||||
size BigInt
|
||||
objectName String
|
||||
uploaderEmail String?
|
||||
uploaderName String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
reverseShareId String
|
||||
reverseShare ReverseShare @relation(fields: [reverseShareId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("reverse_share_files")
|
||||
}
|
||||
|
||||
model ReverseShareAlias {
|
||||
id String @id @default(cuid())
|
||||
alias String @unique
|
||||
reverseShareId String @unique
|
||||
reverseShare ReverseShare @relation(fields: [reverseShareId], references: [id], onDelete: Cascade)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("reverse_share_aliases")
|
||||
}
|
||||
|
||||
enum FieldRequirement {
|
||||
HIDDEN
|
||||
OPTIONAL
|
||||
REQUIRED
|
||||
}
|
||||
|
||||
enum PageLayout {
|
||||
DEFAULT
|
||||
WETRANSFER
|
||||
}
|
||||
|
@@ -1,6 +1,8 @@
|
||||
import { prisma } from "../src/shared/prisma";
|
||||
import crypto from "node:crypto";
|
||||
import { env } from '../src/env';
|
||||
/* eslint-disable no-undef */
|
||||
const { PrismaClient } = require('@prisma/client');
|
||||
const crypto = require('crypto');
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
const defaultConfigs = [
|
||||
// General Configurations
|
||||
@@ -24,7 +26,7 @@ const defaultConfigs = [
|
||||
},
|
||||
{
|
||||
key: "appLogo",
|
||||
value: "https://i.ibb.co/V0hdRtjV/logo.png",
|
||||
value: "https://i.ibb.co/gMpk75bZ/Group.png",
|
||||
type: "string",
|
||||
group: "general",
|
||||
},
|
||||
@@ -37,7 +39,7 @@ const defaultConfigs = [
|
||||
// Storage Configurations
|
||||
{
|
||||
key: "maxFileSize",
|
||||
value: env.MAX_FILESIZE, // default 1GiB in bytes - 1073741824
|
||||
value: "1073741824", // default 1GiB in bytes
|
||||
type: "bigint",
|
||||
group: "storage",
|
||||
},
|
||||
@@ -115,37 +117,111 @@ const defaultConfigs = [
|
||||
type: "string",
|
||||
group: "email",
|
||||
},
|
||||
{
|
||||
key: "smtpSecure",
|
||||
value: "auto",
|
||||
type: "string",
|
||||
group: "email",
|
||||
},
|
||||
{
|
||||
key: "smtpNoAuth",
|
||||
value: "false",
|
||||
type: "boolean",
|
||||
group: "email",
|
||||
},
|
||||
{
|
||||
key: "passwordResetTokenExpiration",
|
||||
value: "3600",
|
||||
type: "number",
|
||||
group: "security",
|
||||
},
|
||||
// OIDC SSO Configurations
|
||||
{
|
||||
key: "oidcEnabled",
|
||||
value: "false",
|
||||
type: "boolean",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcIssuerUrl",
|
||||
value: "",
|
||||
type: "string",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcClientId",
|
||||
value: "",
|
||||
type: "string",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcClientSecret",
|
||||
value: "",
|
||||
type: "string",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcRedirectUri",
|
||||
value: "",
|
||||
type: "string",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcScope",
|
||||
value: "openid profile email",
|
||||
type: "string",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcAutoRegister",
|
||||
value: "true",
|
||||
type: "boolean",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "oidcAdminEmailDomains",
|
||||
value: "",
|
||||
type: "string",
|
||||
group: "oidc",
|
||||
},
|
||||
{
|
||||
key: "serverUrl",
|
||||
value: "http://localhost:3333",
|
||||
type: "string",
|
||||
group: "general",
|
||||
}
|
||||
];
|
||||
|
||||
async function main() {
|
||||
console.log("Seeding app configurations...");
|
||||
console.log("🌱 Starting app configurations seed...");
|
||||
console.log("🛡️ Protected mode: Only creates missing configurations");
|
||||
|
||||
let createdCount = 0;
|
||||
let skippedCount = 0;
|
||||
|
||||
for (const config of defaultConfigs) {
|
||||
if (config.key === "jwtSecret") {
|
||||
const existingSecret = await prisma.appConfig.findUnique({
|
||||
where: { key: "jwtSecret" },
|
||||
});
|
||||
const existingConfig = await prisma.appConfig.findUnique({
|
||||
where: { key: config.key },
|
||||
});
|
||||
|
||||
if (existingSecret) {
|
||||
console.log("JWT secret already exists, skipping...");
|
||||
continue;
|
||||
}
|
||||
if (existingConfig) {
|
||||
console.log(`⏭️ Configuration '${config.key}' already exists, skipping...`);
|
||||
skippedCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
await prisma.appConfig.upsert({
|
||||
where: { key: config.key },
|
||||
update: config,
|
||||
create: config,
|
||||
await prisma.appConfig.create({
|
||||
data: config,
|
||||
});
|
||||
|
||||
console.log(`✅ Created configuration: ${config.key}`);
|
||||
createdCount++;
|
||||
}
|
||||
|
||||
console.log("App configurations seeded successfully!");
|
||||
console.log("\n📊 Seed Summary:");
|
||||
console.log(` ✅ Created: ${createdCount} configurations`);
|
||||
console.log(` ⏭️ Skipped: ${skippedCount} configurations`);
|
||||
console.log("🎉 App configurations seeded successfully!");
|
||||
}
|
||||
|
||||
main()
|
||||
@@ -155,4 +231,4 @@ main()
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
});
|
122
apps/server/reset-password.sh
Executable file
@@ -0,0 +1,122 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Palmr Password Reset Script
|
||||
# This script allows resetting user passwords from within the Docker container
|
||||
|
||||
echo "🔐 Palmr Password Reset Tool"
|
||||
echo "============================="
|
||||
|
||||
# Check if we're in the right directory
|
||||
if [ ! -f "package.json" ]; then
|
||||
echo "❌ Error: This script must be run from the server directory (/app/server)"
|
||||
echo " Current directory: $(pwd)"
|
||||
echo " Expected: /app/server"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Function to check if tsx is available
|
||||
check_tsx() {
|
||||
# Check if tsx binary exists in node_modules
|
||||
if [ -f "node_modules/.bin/tsx" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Fallback: try npx
|
||||
if npx tsx --version >/dev/null 2>&1; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to install only tsx if missing
|
||||
install_tsx_only() {
|
||||
echo "📦 Installing tsx (quick install)..."
|
||||
if command -v pnpm >/dev/null 2>&1; then
|
||||
pnpm add tsx --save-dev --silent 2>/dev/null
|
||||
elif command -v npm >/dev/null 2>&1; then
|
||||
npm install tsx --save-dev --silent 2>/dev/null
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
|
||||
return $?
|
||||
}
|
||||
|
||||
# Function to install all dependencies as fallback
|
||||
install_all_deps() {
|
||||
echo "📦 Installing all dependencies (this may take a moment)..."
|
||||
if command -v pnpm >/dev/null 2>&1; then
|
||||
pnpm install --silent 2>/dev/null
|
||||
elif command -v npm >/dev/null 2>&1; then
|
||||
npm install --silent 2>/dev/null
|
||||
else
|
||||
echo "❌ Error: No package manager found (pnpm/npm)"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to ensure Prisma client is available
|
||||
ensure_prisma() {
|
||||
# Check if Prisma client exists and is valid
|
||||
if [ -d "node_modules/@prisma/client" ] && [ -f "node_modules/@prisma/client/index.js" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "📦 Generating Prisma client..."
|
||||
if npx prisma generate --silent >/dev/null 2>&1; then
|
||||
echo "✅ Prisma client ready"
|
||||
return 0
|
||||
else
|
||||
echo "❌ Error: Failed to generate Prisma client"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Quick checks first
|
||||
echo "🔍 Checking dependencies..."
|
||||
|
||||
# Check tsx availability
|
||||
if check_tsx; then
|
||||
echo "✅ tsx is ready"
|
||||
else
|
||||
echo "📦 tsx not found, installing..."
|
||||
|
||||
# Try quick tsx-only install first
|
||||
if install_tsx_only && check_tsx; then
|
||||
echo "✅ tsx installed successfully"
|
||||
else
|
||||
echo "⚠️ Quick install failed, installing all dependencies..."
|
||||
install_all_deps
|
||||
|
||||
# Final check
|
||||
if ! check_tsx; then
|
||||
echo "❌ Error: tsx is still not available after full installation"
|
||||
echo " Please check your package.json and node_modules"
|
||||
exit 1
|
||||
fi
|
||||
echo "✅ tsx is now ready"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Ensure Prisma client
|
||||
ensure_prisma
|
||||
|
||||
# Check if the TypeScript script exists
|
||||
if [ ! -f "src/scripts/reset-password.ts" ]; then
|
||||
echo "❌ Error: Reset password script not found at src/scripts/reset-password.ts"
|
||||
echo " Available files in src/scripts/:"
|
||||
ls -la src/scripts/ 2>/dev/null || echo " Directory src/scripts/ does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# All checks passed, run the script
|
||||
echo "🚀 Starting password reset tool..."
|
||||
echo ""
|
||||
|
||||
# Execute the script using the most reliable method
|
||||
if [ -f "node_modules/.bin/tsx" ]; then
|
||||
node_modules/.bin/tsx src/scripts/reset-password.ts "$@"
|
||||
else
|
||||
npx tsx src/scripts/reset-password.ts "$@"
|
||||
fi
|
@@ -1,17 +0,0 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
const count = await prisma.user.count();
|
||||
console.log(count);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
@@ -1,27 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "Waiting for PostgreSQL..."
|
||||
while ! nc -z postgres 5432; do
|
||||
sleep 1
|
||||
done
|
||||
echo "PostgreSQL is up!"
|
||||
|
||||
echo "Generating Prisma client..."
|
||||
npx prisma generate --schema=./prisma/schema.prisma
|
||||
|
||||
# Check if database needs migrations
|
||||
echo "Checking migrations..."
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Check if database is empty using Prisma
|
||||
USER_COUNT=$(node ./scripts/check-db.mjs)
|
||||
|
||||
if [ "$USER_COUNT" -eq "0" ]; then
|
||||
echo "Database is empty, running seeds..."
|
||||
pnpm db:seed
|
||||
else
|
||||
echo "Database already has data, skipping seeds..."
|
||||
fi
|
||||
|
||||
echo "Starting application..."
|
||||
pnpm start
|
@@ -1,4 +1,5 @@
|
||||
import { registerSwagger } from "./config/swagger.config";
|
||||
import { envTimeoutOverrides } from "./config/timeout.config";
|
||||
import { prisma } from "./shared/prisma";
|
||||
import fastifyCookie from "@fastify/cookie";
|
||||
import { fastifyCors } from "@fastify/cors";
|
||||
@@ -21,6 +22,14 @@ export async function buildApp() {
|
||||
removeAdditional: false,
|
||||
},
|
||||
},
|
||||
logger: {
|
||||
level: "info",
|
||||
},
|
||||
bodyLimit: 1024 * 1024 * 1024 * 1024 * 1024,
|
||||
connectionTimeout: 0,
|
||||
keepAliveTimeout: envTimeoutOverrides.keepAliveTimeout,
|
||||
requestTimeout: envTimeoutOverrides.requestTimeout,
|
||||
trustProxy: true,
|
||||
}).withTypeProvider<ZodTypeProvider>();
|
||||
|
||||
app.setValidatorCompiler(validatorCompiler);
|
||||
|
@@ -1,13 +0,0 @@
|
||||
import { env } from "../env";
|
||||
import { Client } from "minio";
|
||||
|
||||
export const minioLocalClient = new Client({
|
||||
endPoint: env.MINIO_ENDPOINT === "minio" ? env.SERVER_IP : env.MINIO_ENDPOINT,
|
||||
port: Number(env.MINIO_PORT),
|
||||
useSSL: env.MINIO_USE_SSL === "true",
|
||||
accessKey: env.MINIO_ROOT_USER,
|
||||
secretKey: env.MINIO_ROOT_PASSWORD,
|
||||
region: env.MINIO_REGION,
|
||||
});
|
||||
|
||||
export const bucketName = env.MINIO_BUCKET_NAME;
|
@@ -1,13 +0,0 @@
|
||||
import { env } from "../env";
|
||||
import { Client } from "minio";
|
||||
|
||||
export const minioClient = new Client({
|
||||
endPoint: env.MINIO_ENDPOINT,
|
||||
port: Number(env.MINIO_PORT),
|
||||
useSSL: env.MINIO_USE_SSL === "true",
|
||||
accessKey: env.MINIO_ROOT_USER,
|
||||
secretKey: env.MINIO_ROOT_PASSWORD,
|
||||
region: env.MINIO_REGION,
|
||||
});
|
||||
|
||||
export const bucketName = env.MINIO_BUCKET_NAME;
|
33
apps/server/src/config/storage.config.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
import { env } from "../env";
|
||||
import { StorageConfig } from "../types/storage";
|
||||
import { S3Client } from "@aws-sdk/client-s3";
|
||||
|
||||
export const storageConfig: StorageConfig = {
|
||||
endpoint: env.S3_ENDPOINT || "",
|
||||
port: env.S3_PORT ? Number(env.S3_PORT) : undefined,
|
||||
useSSL: env.S3_USE_SSL === "true",
|
||||
accessKey: env.S3_ACCESS_KEY || "",
|
||||
secretKey: env.S3_SECRET_KEY || "",
|
||||
region: env.S3_REGION || "",
|
||||
bucketName: env.S3_BUCKET_NAME || "",
|
||||
forcePathStyle: env.S3_FORCE_PATH_STYLE === "true",
|
||||
};
|
||||
|
||||
export const s3Client =
|
||||
env.ENABLE_S3 === "true"
|
||||
? new S3Client({
|
||||
endpoint: storageConfig.useSSL
|
||||
? `https://${storageConfig.endpoint}${storageConfig.port ? `:${storageConfig.port}` : ""}`
|
||||
: `http://${storageConfig.endpoint}${storageConfig.port ? `:${storageConfig.port}` : ""}`,
|
||||
region: storageConfig.region,
|
||||
credentials: {
|
||||
accessKeyId: storageConfig.accessKey,
|
||||
secretAccessKey: storageConfig.secretKey,
|
||||
},
|
||||
forcePathStyle: storageConfig.forcePathStyle,
|
||||
})
|
||||
: null;
|
||||
|
||||
export const bucketName = storageConfig.bucketName;
|
||||
|
||||
export const isS3Enabled = env.ENABLE_S3 === "true";
|
@@ -15,6 +15,7 @@ export function registerSwagger(app: any) {
|
||||
name: "Authentication",
|
||||
description: "Authentication related endpoints",
|
||||
},
|
||||
{ name: "OIDC", description: "OpenID Connect authentication endpoints" },
|
||||
{ name: "User", description: "User management endpoints" },
|
||||
{ name: "File", description: "File management endpoints" },
|
||||
{ name: "Share", description: "File sharing endpoints" },
|
||||
|
73
apps/server/src/config/timeout.config.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
/**
|
||||
* Timeout Configuration for Large File Handling
|
||||
*
|
||||
* These settings control how long the server will wait for various operations
|
||||
* when dealing with large files. Adjust based on your infrastructure needs.
|
||||
*/
|
||||
|
||||
export const timeoutConfig = {
|
||||
connection: {
|
||||
timeout: 0,
|
||||
keepAlive: 20 * 60 * 60 * 1000, // 20 hours in milliseconds
|
||||
},
|
||||
|
||||
request: {
|
||||
timeout: 0,
|
||||
bodyTimeout: 0, // Disabled for large files
|
||||
},
|
||||
|
||||
file: {
|
||||
uploadTimeout: 0,
|
||||
|
||||
downloadTimeout: 0,
|
||||
streamTimeout: 30 * 1000, // 30 seconds between chunks
|
||||
},
|
||||
|
||||
token: {
|
||||
expiration: 60 * 60 * 1000, // 1 hour in milliseconds
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Get timeout configuration based on file size
|
||||
* For very large files, we might want different timeouts
|
||||
*/
|
||||
export function getTimeoutForFileSize(fileSizeBytes: number) {
|
||||
const fileSizeGB = fileSizeBytes / (1024 * 1024 * 1024);
|
||||
|
||||
if (fileSizeGB > 100) {
|
||||
return {
|
||||
...timeoutConfig,
|
||||
token: {
|
||||
expiration: 24 * 60 * 60 * 1000, // 24 hours for very large files
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
if (fileSizeGB > 10) {
|
||||
return {
|
||||
...timeoutConfig,
|
||||
token: {
|
||||
expiration: 4 * 60 * 60 * 1000, // 4 hours for large files
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return timeoutConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Environment-based timeout overrides
|
||||
* You can set these in your .env file to override defaults
|
||||
*/
|
||||
export const envTimeoutOverrides = {
|
||||
keepAliveTimeout: process.env.KEEP_ALIVE_TIMEOUT
|
||||
? parseInt(process.env.KEEP_ALIVE_TIMEOUT)
|
||||
: timeoutConfig.connection.keepAlive,
|
||||
|
||||
requestTimeout: process.env.REQUEST_TIMEOUT ? parseInt(process.env.REQUEST_TIMEOUT) : timeoutConfig.request.timeout,
|
||||
|
||||
tokenExpiration: process.env.TOKEN_EXPIRATION
|
||||
? parseInt(process.env.TOKEN_EXPIRATION)
|
||||
: timeoutConfig.token.expiration,
|
||||
};
|
@@ -1,18 +1,18 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const envSchema = z.object({
|
||||
FRONTEND_URL: z.string().url().min(1),
|
||||
MINIO_ENDPOINT: z.string().min(1),
|
||||
MINIO_PORT: z.string().min(1),
|
||||
MINIO_USE_SSL: z.string().min(1),
|
||||
MINIO_ROOT_PASSWORD: z.string().min(1),
|
||||
MINIO_ROOT_USER: z.string().min(1),
|
||||
MINIO_REGION: z.string().min(1),
|
||||
MINIO_BUCKET_NAME: z.string().min(1),
|
||||
PORT: z.string().min(1),
|
||||
DATABASE_URL: z.string().min(1),
|
||||
SERVER_IP: z.string().min(1),
|
||||
MAX_FILESIZE: z.string().min(1),
|
||||
ENABLE_S3: z.union([z.literal("true"), z.literal("false")]).default("false"),
|
||||
ENCRYPTION_KEY: z.string().optional().default("palmr-default-encryption-key-2025"),
|
||||
S3_ENDPOINT: z.string().optional(),
|
||||
S3_PORT: z.string().optional(),
|
||||
S3_USE_SSL: z.string().optional(),
|
||||
S3_ACCESS_KEY: z.string().optional(),
|
||||
S3_SECRET_KEY: z.string().optional(),
|
||||
S3_REGION: z.string().optional(),
|
||||
S3_BUCKET_NAME: z.string().optional(),
|
||||
S3_FORCE_PATH_STYLE: z.union([z.literal("true"), z.literal("false")]).default("false"),
|
||||
SECURE_SITE: z.union([z.literal("true"), z.literal("false")]).default("false"),
|
||||
DATABASE_URL: z.string().optional().default("file:/app/server/prisma/palmr.db"),
|
||||
});
|
||||
|
||||
export const env = envSchema.parse(process.env);
|
||||
|
@@ -1,10 +1,25 @@
|
||||
import { EmailService } from "../email/service";
|
||||
import { LogoService } from "./logo.service";
|
||||
import { AppService } from "./service";
|
||||
import { FastifyReply, FastifyRequest } from "fastify";
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
|
||||
const uploadsDir = path.join(process.cwd(), 'uploads/logo');
|
||||
const isDocker = (() => {
|
||||
try {
|
||||
require("fs").statSync("/.dockerenv");
|
||||
return true;
|
||||
} catch {
|
||||
try {
|
||||
return require("fs").readFileSync("/proc/self/cgroup", "utf8").includes("docker");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
const baseDir = isDocker ? "/app/server" : process.cwd();
|
||||
const uploadsDir = path.join(baseDir, "uploads/logo");
|
||||
if (!fs.existsSync(uploadsDir)) {
|
||||
fs.mkdirSync(uploadsDir, { recursive: true });
|
||||
}
|
||||
@@ -12,6 +27,7 @@ if (!fs.existsSync(uploadsDir)) {
|
||||
export class AppController {
|
||||
private appService = new AppService();
|
||||
private logoService = new LogoService();
|
||||
private emailService = new EmailService();
|
||||
|
||||
async getAppInfo(request: FastifyRequest, reply: FastifyReply) {
|
||||
try {
|
||||
@@ -56,6 +72,24 @@ export class AppController {
|
||||
}
|
||||
}
|
||||
|
||||
async testSmtpConnection(request: FastifyRequest, reply: FastifyReply) {
|
||||
try {
|
||||
await request.jwtVerify();
|
||||
|
||||
if (!(request as any).user?.isAdmin) {
|
||||
return reply.status(403).send({ error: "Access restricted to administrators" });
|
||||
}
|
||||
|
||||
const body = request.body as any;
|
||||
const smtpConfig = body.smtpConfig || undefined;
|
||||
|
||||
const result = await this.emailService.testConnection(smtpConfig);
|
||||
return reply.send(result);
|
||||
} catch (error: any) {
|
||||
return reply.status(400).send({ error: error.message });
|
||||
}
|
||||
}
|
||||
|
||||
async uploadLogo(request: FastifyRequest, reply: FastifyReply) {
|
||||
try {
|
||||
const file = await request.file();
|
||||
@@ -63,7 +97,7 @@ export class AppController {
|
||||
return reply.status(400).send({ error: "No file uploaded" });
|
||||
}
|
||||
|
||||
if (!file.mimetype.startsWith('image/')) {
|
||||
if (!file.mimetype.startsWith("image/")) {
|
||||
return reply.status(400).send({ error: "Only images are allowed" });
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,7 @@
|
||||
import sharp from "sharp";
|
||||
import { prisma } from "../../shared/prisma";
|
||||
import sharp from "sharp";
|
||||
|
||||
export class LogoService {
|
||||
|
||||
async uploadLogo(buffer: Buffer): Promise<string> {
|
||||
try {
|
||||
const metadata = await sharp(buffer).metadata();
|
||||
@@ -11,20 +10,20 @@ export class LogoService {
|
||||
}
|
||||
|
||||
const webpBuffer = await sharp(buffer)
|
||||
.resize(100, 100, {
|
||||
.resize(100, 100, {
|
||||
fit: "contain",
|
||||
background: { r: 255, g: 255, b: 255, alpha: 0 } // Fundo transparente
|
||||
background: { r: 255, g: 255, b: 255, alpha: 0 },
|
||||
})
|
||||
.webp({
|
||||
.webp({
|
||||
quality: 60,
|
||||
effort: 6,
|
||||
nearLossless: true,
|
||||
alphaQuality: 100, // Melhor qualidade para transparência
|
||||
lossless: true // Preserva melhor a transparência
|
||||
alphaQuality: 100,
|
||||
lossless: true,
|
||||
})
|
||||
.toBuffer();
|
||||
|
||||
return `data:image/webp;base64,${webpBuffer.toString('base64')}`;
|
||||
return `data:image/webp;base64,${webpBuffer.toString("base64")}`;
|
||||
} catch (error) {
|
||||
console.error("Error processing logo:", error);
|
||||
throw error;
|
||||
@@ -34,9 +33,9 @@ export class LogoService {
|
||||
async deleteLogo(): Promise<void> {
|
||||
try {
|
||||
await prisma.appConfig.update({
|
||||
where: { key: 'appLogo' },
|
||||
where: { key: "appLogo" },
|
||||
data: {
|
||||
value: '',
|
||||
value: "",
|
||||
updatedAt: new Date(),
|
||||
},
|
||||
});
|
||||
|
@@ -10,13 +10,13 @@ export async function appRoutes(app: FastifyInstance) {
|
||||
const adminPreValidation = async (request: any, reply: any) => {
|
||||
try {
|
||||
const usersCount = await prisma.user.count();
|
||||
|
||||
|
||||
if (usersCount <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
await request.jwtVerify();
|
||||
|
||||
|
||||
if (!request.user.isAdmin) {
|
||||
return reply.status(403).send({
|
||||
error: "Access restricted to administrators",
|
||||
@@ -126,6 +126,59 @@ export async function appRoutes(app: FastifyInstance) {
|
||||
appController.bulkUpdateConfigs.bind(appController)
|
||||
);
|
||||
|
||||
app.post(
|
||||
"/app/test-smtp",
|
||||
{
|
||||
preValidation: adminPreValidation,
|
||||
schema: {
|
||||
tags: ["App"],
|
||||
operationId: "testSmtpConnection",
|
||||
summary: "Test SMTP connection with provided or saved configuration",
|
||||
description:
|
||||
"Validates SMTP connectivity using either provided configuration parameters or the currently saved settings. This endpoint allows testing SMTP settings before saving them permanently. Requires admin privileges.",
|
||||
body: z
|
||||
.object({
|
||||
smtpConfig: z
|
||||
.object({
|
||||
smtpEnabled: z.string().describe("Whether SMTP is enabled ('true' or 'false')"),
|
||||
smtpHost: z.string().describe("SMTP server hostname or IP address (e.g., 'smtp.gmail.com')"),
|
||||
smtpPort: z
|
||||
.union([z.string(), z.number()])
|
||||
.transform(String)
|
||||
.describe("SMTP server port (typically 587 for TLS, 25 for non-secure)"),
|
||||
smtpUser: z.string().describe("Username for SMTP authentication (e.g., email address)"),
|
||||
smtpPass: z.string().describe("Password for SMTP authentication (for Gmail, use App Password)"),
|
||||
smtpSecure: z
|
||||
.string()
|
||||
.optional()
|
||||
.describe("Connection security method ('auto', 'ssl', 'tls', or 'none')"),
|
||||
smtpNoAuth: z.string().optional().describe("Disable SMTP authentication ('true' or 'false')"),
|
||||
})
|
||||
.optional()
|
||||
.describe("SMTP configuration to test. If not provided, uses currently saved configuration"),
|
||||
})
|
||||
.optional()
|
||||
.describe("Request body containing SMTP configuration to test. Send empty body to test saved configuration"),
|
||||
response: {
|
||||
200: z.object({
|
||||
success: z.boolean().describe("Whether the SMTP connection test was successful"),
|
||||
message: z.string().describe("Descriptive message about the test result"),
|
||||
}),
|
||||
400: z.object({
|
||||
error: z.string().describe("Error message describing what went wrong with the test"),
|
||||
}),
|
||||
401: z.object({
|
||||
error: z.string().describe("Authentication error - invalid or missing JWT token"),
|
||||
}),
|
||||
403: z.object({
|
||||
error: z.string().describe("Authorization error - user does not have admin privileges"),
|
||||
}),
|
||||
},
|
||||
},
|
||||
},
|
||||
appController.testSmtpConnection.bind(appController)
|
||||
);
|
||||
|
||||
app.post(
|
||||
"/app/logo",
|
||||
{
|
||||
|