yakenator 098b55e3b0 feat: initial Jimi Gallery prototype
- Public site (Home/Artists/Exhibitions/News/About/Contact) with EN/KO/JA i18n
- Admin panel with login, CRUD, image upload, multilingual editing
- Exhibition slider/lightbox view
- FastAPI + MongoDB backend, JWT auth
- Docker Compose deployment, behind nginx at jimi.yakenator.io
2026-04-25 12:47:36 +09:00
2026-04-25 12:47:36 +09:00
2026-04-25 12:47:36 +09:00

Jimi Gallery

Contemporary art gallery website prototype — public site + admin panel. Design language inspired by Jack Shainman, Crossing Art, and Derek Eller.

Stack

  • Frontend: Vanilla HTML/CSS/JS (no build step). i18n in EN/KO/JA. Exhibition slider. Per-field image upload with client-side downscale.
  • Backend: FastAPI + Motor (async MongoDB driver) + PyJWT.
  • Database: MongoDB 7.
  • Deploy: Docker Compose — single-command bring-up.

Brand mark: purple circle with serif JM monogram (inline SVG in assets/app.js and admin/admin.js), paired with a JIMI GALLERY wordmark in Cinzel.

Run it

cd /Users/jungwoochoi/Desktop/prototype/gallery
docker compose up --build

Then visit:

Ports (deliberately uncommon to avoid local collisions):

Service Host port Container port
API + static 5891 8000
MongoDB 47017 27017

First boot auto-seeds the demo data. Subsequent boots persist to the mongo_data volume.

Environment

Override via shell env or a .env at the repo root:

ADMIN_PASSWORD=your-password
JWT_SECRET=change-me-to-a-long-random-string

backend/.env.example lists all knobs.

Structure

gallery/
├── index.html, artists.html, ...           public site pages
├── assets/
│   ├── data.js            Store (API-backed, cached) + Auth (JWT)
│   ├── i18n.js            EN/KO/JA dictionary, detection, switcher helpers
│   ├── app.js             nav + footer + slider helpers
│   └── styles.css
├── admin/
│   ├── index.html         login
│   ├── dashboard.html, artists.html, exhibitions.html, news.html, settings.html
│   ├── admin.js           sidebar, image field, multilingual field, export/import
│   └── admin.css
├── backend/
│   ├── main.py            FastAPI routes + static mount
│   ├── db.py              Motor client
│   ├── auth.py            JWT issue/verify
│   ├── seed.py            demo seed
│   ├── requirements.txt
│   ├── Dockerfile
│   └── .env.example
└── docker-compose.yml

API surface

All writes require Authorization: Bearer <jwt>; reads are public.

POST   /api/auth/login         → {token}
GET    /api/auth/me            → {ok: true}

GET    /api/settings
PUT    /api/settings

GET    /api/artists
GET    /api/artists/{id}
PUT    /api/artists/{id}
DELETE /api/artists/{id}

GET    /api/exhibitions
GET    /api/exhibitions/{id}
PUT    /api/exhibitions/{id}
DELETE /api/exhibitions/{id}

GET    /api/news
GET    /api/news/{id}
PUT    /api/news/{id}
DELETE /api/news/{id}

POST   /api/admin/seed         reset all collections to demo seed
GET    /api/admin/export       full DB snapshot
POST   /api/admin/import       replace full DB with uploaded snapshot

Interactive docs (Swagger UI) at http://localhost:5891/docs.

Frontend data access pattern

// On every page — inline script pattern:
(async () => {
  await Store.load();            // fetches /api/settings + /api/artists + /api/exhibitions + /api/news, caches
  renderChrome("home");
  // ... accessors below are sync reads from cache ...
  Store.artists();
  Store.exhibition(id);
})();

// Admin mutations are async:
await Store.upsert("artists", artist);
await Store.remove("news", id);
await Store.updateSettings({...});
await Store.reset();
await Store.importAll(json);
await Store.exportAll();

Auth:

await Auth.login(password);    // posts to /api/auth/login, stores JWT in localStorage
Auth.isAuthed();               // sync — presence check; API returns 401 if expired
Auth.logout();                 // clears token

Dev (no Docker)

If you want to iterate on the backend without rebuilding the image:

# Mongo (container only — still uncommon port)
docker run -d -p 47017:27017 --name jimi-mongo mongo:7

# Backend
cd backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
MONGO_URL=mongodb://localhost:47017 STATIC_DIR=.. \
  uvicorn main:app --reload --port 5891

Hot-reload on Python changes, frontend edits land on browser refresh.

Description
Jimi Gallery — contemporary art gallery prototype. FastAPI + MongoDB backend, vanilla HTML/JS frontend, EN/KO/JA i18n. Deployed at https://jimi.yakenator.io
Readme 87 KiB
Languages
HTML 36.9%
JavaScript 27.4%
Python 22.4%
CSS 12.9%
Dockerfile 0.4%