Spaces:
Running
Download README.md from stevafernandes/CURAS: direct link, hf CLI and curl.
- Browser
- Download file 7.4 kB
-
https://huggingface.co/spaces/stevafernandes/CURAS/resolve/main/README.md
- Command line
-
hf download hf://spaces/stevafernandes/CURAS/README.md
-
curl -L -o README.md https://huggingface.co/spaces/stevafernandes/CURAS/resolve/main/README.md
title: CURAS Research Database
colorFrom: gray
colorTo: gray
sdk: docker
app_port: 7860
pinned: false
CURAS Research Database
A public database of undergraduate research opportunities posted and updated by the Center for Undergraduate Research and Scholarship (CURAS). Faculty submit new listings or updates through a form, a CURAS administrator approves them, and approved listings appear on the public page immediately.
- Public page (
/): search and filter listings by area of study (several at once), type of opportunity, term and standing. Listings are headed by the faculty member's name, every listing states that it is open to Creighton students only, and each area of study is shown as a colour-coded tag (the colours are defined inapp/fields.pyandapp/static/style.css). Each listing has a permanent link (/listings/<id>). The pages use Creighton's brand palette (Pantone 286 C blue, #0054A6). - Submission form (
/submit): faculty enter their name and NetID plus every listing field. Choosing an existing listing pre-fills the form to propose an update. - Admin (
/admin): shared-password sign-in. Review pending submissions (updates show a side-by-side comparison with the current listing), approve or reject, edit, retire and restore listings, add a listing directly, export everything as CSV.
Data lives in Supabase (Postgres). The application talks to Supabase only from the server
with the service_role key; Row Level Security is enabled with no policies, so the public
anon key can neither read nor write the tables.
One-time setup
1. Create the tables in Supabase
In the Supabase dashboard open SQL Editor, paste the contents of
supabase/schema.sql and run it. It creates two tables,
listings and submissions, and locks them down.
2. Collect the four secrets
| Secret | Where it comes from |
|---|---|
SUPABASE_URL |
Supabase dashboard: the Connect button at the top of the project, or Settings, Data API. It looks like https://<ref>.supabase.co |
SUPABASE_SERVICE_ROLE_KEY |
Settings, API Keys: create or copy a Secret key (starts with sb_secret_). On older projects the legacy service_role key under the "Legacy API keys" tab also works. Never the publishable or anon key, and never put it in a browser |
ADMIN_PASSWORD |
A long password you choose (at least 12 characters). Everyone who approves listings uses it. |
SESSION_SECRET |
Any long random string (for example 48 random characters). Signs the admin session cookie. |
3. Load the existing listings (once)
In the SQL Editor, paste the contents of supabase/seed_listings.sql
and run it. It inserts the 50 listings from the September 2026 workbook as published
listings and ends by reporting listings_loaded = 50. It refuses to run a second time, so
it cannot create duplicates.
Nothing needs to be installed or run on your own computer. (If you ever receive a newer
workbook, scripts/import_excel.py converts it to seed/listings_seed.json and
scripts/make_seed_sql.py regenerates the SQL file; both need Python with
scripts/requirements-dev.txt installed. scripts/seed_supabase.py is an alternative that
loads the JSON through the API using a .env file.)
4. Deploy on Hugging Face
- Create a new Space: Docker SDK, CPU basic hardware, visibility of your choice (the public page needs to be public for students to see it).
- Upload these files, keeping the folder structure:
Dockerfile,requirements.txt,README.mdand the wholeapp/folder. (supabase/,scripts/,seed/andtests/are not needed on the Space but are harmless if uploaded.) - In the Space, open Settings, then Variables and secrets, and add the four secrets from step 2 as Secrets (not public variables).
- The Space builds and starts. Check
https://<owner>-<space-name>.hf.space/healthz; it should report"db_configured": trueand"admin_configured": true. - Share the direct address
https://<owner>-<space-name>.hf.space/with students and faculty. The Space page on huggingface.co shows the same site inside a frame, which works for browsing and submitting but not for admin sign-in (see below).
Optional settings (add as Variables if you need them): APP_TIMEZONE (default
America/Chicago, the calendar day stamped on "Updated"), SESSION_HOURS (default 8),
CACHE_SECONDS (default 60, how long the public page may show cached listings).
5. Sign in as admin
Open the Space directly at its own address, https://<owner>-<space-name>.hf.space/admin/login,
not inside the Space page on huggingface.co. The sign-in cookie is only sent to the
site's own address, so signing in inside the embedded frame does not work (the page says
so and links to the direct address). Sessions last 8 hours. After 5 wrong passwords from
one network the sign-in waits 15 minutes.
To change the admin password, change the ADMIN_PASSWORD secret and restart the Space.
Changing SESSION_SECRET signs every admin out.
How approval works
- A faculty member submits the form. The submission is stored with status
pendingand is not public. - An admin opens Admin, reviews it and clicks Approve and publish (or rejects it with an optional note that stays private).
- On approval a new listing is created, or, for an update, the existing listing is replaced and its "Updated" date set to today. The public page shows the change immediately.
Listings are never deleted from the admin pages; Retire hides a listing and Restore brings it back. An update approved for a retired listing changes its content but leaves it retired until an admin restores it.
Listings imported from the workbook that lack one of the required fields (for example a standing or an area of study) can still be edited and updated without inventing that content; brand-new listings must fill every required field.
Running locally
Requires Docker (for a Postgres + PostgREST stand-in that behaves like Supabase's REST API) and Python 3.12 or newer.
pip install -r requirements.txt -r scripts/requirements-dev.txt
docker compose -f .local/docker-compose.yml up -d
python scripts/seed_supabase.py --env .local/.env.local
.local/run_local.sh # serves http://127.0.0.1:7861
python -m pytest -q tests # unit tests plus every public and admin flow
.local/.env.local holds throw-away local credentials only (and sets COOKIE_SECURE=false
because the local server is plain http). The real .env is ignored by git and must never
be uploaded to the Space (use Space secrets instead).
Project layout
app/main.py routes (public, submission, admin)
app/services.py validation, filtering, approval logic
app/fields.py the single definition of every listing field and vocabulary
app/normalize.py turns messy multi-value text into vocabulary items
app/db.py Supabase REST (PostgREST) client
app/security.py sessions, CSRF tokens, rate limiting
app/templates/ Jinja2 templates
app/static/ style.css, app.js
scripts/ import_excel.py, seed_supabase.py
seed/ listings_seed.json generated from the workbook
supabase/schema.sql database schema
tests/ pytest suite