Fujimod
브라우저에서 카메라 펌웨어를 시험하고 Fujimod SD 부팅 파일을 만든다
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
프로젝트 폴더에서 /nomorevibe verify를 실행하면 소유권을 확인하고 소개를 직접 관리할 수 있습니다.
1분 만에 확인하기AI photo sharing
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Event photos, found by face. Photographers upload an event once. Guests take a selfie and get back only the photos they're in.
For guests
For photographers and event owners
Accounts
Browser ── presigned PUT ──▶ S3 events/{event_id}/originals/{photo_id}.ext
│
└─ POST /photos/upload-complete ─▶ photo row (status = pending)
│
background photo worker
│
┌───────────────────────────┼────────────────────────────┐
▼ ▼ ▼
read dimensions make thumbnail + preview Rekognition IndexFaces
(Pillow) ─▶ S3 (thumbnails/) (event's own collection)
│
▼
faces rows written, photo marked processed
PHOTO_WORKER_CONCURRENCY, REKOGNITION_MAX_TPS).cron_worker.py runs once on container start and resets photos or guests left stuck by an interrupted run.Guest selfie ─▶ Rekognition SearchFacesByImage (event collection)
─▶ matched photo ids, de-duplicated, best match first
─▶ guest record updated
─▶ gallery rendered with presigned S3 URLs
Each event gets its own Rekognition collection, so guests can only ever match inside the event they opened.
| Layer | Technology |
|---|---|
| Backend | Python 3.12, FastAPI, Uvicorn |
| Frontend | Next.js 16, React 19, Tailwind CSS v4, shadcn/ui |
| Database | SQLite via aiosqlite |
| Face recognition | AWS Rekognition |
| File storage | AWS S3 |
| Auth | JWT, bcrypt, optional Google OAuth 2.0 |
| Any SMTP server (printed to the console if none is set) | |
| Packaging | Docker and Docker Compose; pip (backend), bun (frontend) |
| Need | Why |
|---|---|
| Docker and Docker Compose | Runs the whole stack |
| An AWS account, an S3 bucket, and an IAM user | Photo storage and face matching |
| Python 3.12+ and Bun 1.3+ | Only for local development |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:PutObject", "s3:GetObject", "s3:DeleteObject", "s3:ListBucket"],
"Resource": [
"arn:aws:s3:::YOUR_BUCKET_NAME",
"arn:aws:s3:::YOUR_BUCKET_NAME/*"
]
},
{
"Effect": "Allow",
"Action": [
"rekognition:CreateCollection",
"rekognition:DeleteCollection",
"rekognition:IndexFaces",
"rekognition:SearchFacesByImage",
"rekognition:ListCollections"
],
"Resource": "*"
}
]
}
Browsers upload straight to S3, so the bucket also needs a CORS rule for your frontend's origin. backend/set_s3_cors.py sets one up.
backend/.envAt minimum:
SECRET_KEY=<32+ random characters>
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_REGION=us-east-1
S3_BUCKET_NAME=your-bucket
Generate a key with:
python -c "import secrets; print(secrets.token_hex(32))"
Everything else has a default. See Configuration.
docker-compose up -d
| Service | Container | URL |
|---|---|---|
| Frontend | pixello-frontend | http://localhost:3005 |
| Backend API | pixello-backend | http://localhost:8000 |
| Interactive API docs | http://localhost:8000/docs |
The data/ folder is mounted into the backend container, so the SQLite database and staging files survive restarts.
SMTP_HOST set, the confirmation link is printed in the backend logs (docker logs pixello-backend).All backend settings are environment variables, read from backend/.env. Defaults are in backend/app/core/config.py.
| Variable | Description | Default |
|---|---|---|
SECRET_KEY | Required, 32+ characters. Signs JWTs. Changing it logs everyone out and invalidates client selection sessions. | none (app won't start) |
ALGORITHM | JWT algorithm | HS256 |
ACCESS_TOKEN_EXPIRE_MINUTES | Login token lifetime | 1440 |
FRONTEND_URL | Used for links in emails and for the CORS origin | http://localhost:3000 |
| Variable | Description | Default |
|---|---|---|
SMTP_HOST | Mail server. Empty means emails are printed to the backend console (fine locally, not for real users). | empty |
SMTP_PORT | Mail server port | 587 |
SMTP_USERNAME / SMTP_PASSWORD | Mail login, if the server needs one | empty |
SMTP_USE_SSL | true = TLS from the start (usually port 465); false = STARTTLS | false |
EMAIL_FROM | Sender shown on emails | Pixello <no-reply@localhost> |
EMAIL_VERIFY_EXPIRE_HOURS | How long the confirmation link works | 24 |
PASSWORD_RESET_EXPIRE_MINUTES | How long the reset link works | 60 |
| Variable | Description | Default |
|---|---|---|
GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET | From Google Cloud Console → APIs & Services → Credentials → OAuth client ID → Web application. Empty hides the button. | empty |
GOOGLE_REDIRECT_URI | The API's /auth/google/callback as the browser reaches it (behind the frontend proxy: https://your-site/api/auth/google/callback). Add the same URL under Authorized redirect URIs. | http://localhost:8000/auth/google/callback |
| Variable | Description | Default |
|---|---|---|
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY | IAM credentials | required |
AWS_REGION | Region for S3 and Rekognition | us-east-1 |
S3_BUCKET_NAME | Bucket for photos and thumbnails | required |
REKOGNITION_FACE_MATCH_THRESHOLD | Minimum match confidence, 0–100 | 80.0 |
REKOGNITION_MAX_TPS | Max IndexFaces calls per second. AWS's default quota is 50 in us-east-1, us-west-2 and eu-west-1, and 5 elsewhere. | 5 |
PHOTO_WORKER_CONCURRENCY | Photos processed at once. Each decodes a full-size image, so keep it low on a laptop. | 4 |
| Variable | Description | Default |
|---|---|---|
PAYMENT_REQUIRED | If false, owners can skip checkout (dev only) | false |
PAYMENT_PROVIDER | Only mock (simulated checkout) exists today | mock |
PAYMENT_CURRENCY | Currency code | usd |
PRICE_PER_GB_CENTS | Price per GB of event storage, in cents | 100 |
PRICE_FACE_SCAN_CENTS / PRICE_SELECTION_CENTS | Flat per-event add-on, in cents. 0 = included. | 0 / 0 |
MIN_STORAGE_GB / MAX_STORAGE_GB | Allowed storage when creating an event | 1 / 1000 |
| Variable | Description | Default |
|---|---|---|
DB_PATH | SQLite file | data/app.db |
UPLOAD_ROOT | Local staging for originals | data/uploads/originals |
THUMBNAIL_ROOT | Local staging for thumbnails | data/thumbnails |
GUEST_SELFIES_DIR | Guest selfies | data/uploads/selfies |
INGEST_QUEUE_URL, LIVE_POLL_SECONDS, LIVE_SAFETY_SCAN_SECONDS | Live-mode settings (see limits) | empty / 15 / 300 |
The frontend reads one variable, NEXT_PUBLIC_API_URL. In Docker it is /api (a proxy to the backend). For local development set it to http://localhost:8000.
cd backend
python -m venv venv
.\venv\Scripts\activate # Windows
# source venv/bin/activate # macOS / Linux
pip install -r requirements.txt
uvicorn app.main:app --reload
The API runs at http://localhost:8000. To run the stuck-record recovery pass by hand:
python cron_worker.py
reset_app.py wipes the local database and data folders. It is a development utility, so use it carefully.
cd frontend
bun install
echo NEXT_PUBLIC_API_URL=http://localhost:8000 > .env.local
bun run dev
The app runs at http://localhost:3000, matching the default FRONTEND_URL.
PICSHARE/
├── backend/
│ ├── app/
│ │ ├── api/
│ │ │ ├── auth.py # register, login, verify email, password reset
│ │ │ ├── oauth.py # Sign in with Google
│ │ │ ├── events.py # event CRUD, public listing, storage stats
│ │ │ ├── photos.py # presigned uploads, status, gallery, delete, download
│ │ │ ├── guests.py # selfie requests, matches, ZIP download
│ │ │ ├── selection.py # client photo-selection links and picks
│ │ │ └── payments.py # checkout, confirm, skip
│ │ ├── core/config.py # settings (reads .env)
│ │ ├── services/
│ │ │ ├── db.py # SQLite connection, schema, migrations
│ │ │ ├── photo_worker.py # background processing queue
│ │ │ ├── rekognition_service.py # collections, IndexFaces, SearchFaces
│ │ │ ├── s3_service.py # presigned URLs, delete, storage size
│ │ │ ├── thumbnail_service.py # thumbnails and previews
│ │ │ ├── email_service.py # SMTP or console output
│ │ │ ├── payment_service.py # payment provider hook (mock)
│ │ │ ├── live_ingest.py # FTP/SFTP live mode (switched off)
│ │ │ └── recovery.py # reset stuck photos and guests
│ │ └── main.py # app, CORS, routers, worker lifecycle
│ ├── cron_worker.py # one-shot recovery on container start
│ ├── set_s3_cors.py # configure bucket CORS for browser uploads
│ ├── setup_live_ingest.py # SQS setup for live mode
│ └── Dockerfile
├── frontend/
│ └── src/
│ ├── app/ # App Router pages
│ │ ├── dashboard/ # events, new event, payment, event detail
│ │ ├── event/[slug]/ # guest portal and gallery
│ │ ├── select/[token] # client photo selection
│ │ ├── login, register, forgot-password, reset-password, verify-email, oauth/
│ │ └── events/ # public event listing
│ ├── components/ # UI, dashboard, auth and gallery components
│ └── lib/ # API client, upload engine and worker, QR card, auth hook
├── docker-compose.yml
├── CONTRIBUTING.md
└── SECURITY.md
Full, interactive docs are at /docs on the running backend.
| Prefix | Purpose |
|---|---|
/auth | Register, login, email verification, password reset, /me, Google sign-in |
/events | Event CRUD, public listing and lookup, secret-code check, storage usage |
/photos | Upload URLs and completion, status, gallery, retry, delete (single and bulk), original, thumbnail and download URLs |
/guests | Selfie request, status polling, matches, ZIP download, delete |
/selection | Owner side: create and manage client selection links, export picks |
/select | Client side: enter code, browse previews, pick, submit |
/payments | Pricing config, checkout, confirm, skip |
SQLite, created automatically on first start at DB_PATH. New columns are added by small startup migrations in backend/app/services/db.py.
| Table | Holds |
|---|---|
users, auth_tokens, oauth_identities | Accounts, email and reset tokens, linked Google identities |
events | Event details, owner, plan, storage, payment status, optional secret code |
photos | S3 keys, dimensions, face count, processing status, retries |
faces | Rekognition face id per detected face |
guests | Guest requests, selfie path, match results |
selection_links, selections | Client selection links and the photos each client picked |
mock provider exists. A real gateway (for example Stripe) plugs into app/services/payment_service.py.main.py until it is finished.The full list of what's done, in progress and still to do is in CHANGELOG.md.