Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
aa25cb3
feat(board): complete PostgreSQL migration - entities, repos, service…
IbraTech04 May 8, 2026
c361ec5
feat(board): PostgreSQL migration + model normalization
IbraTech04 May 8, 2026
c154be0
feat(agent): device control plane foundation - entities, enrollment, …
IbraTech04 May 9, 2026
fe90ce7
refactor(board): finish device-centric migration cleanup
IbraTech04 May 9, 2026
b8fad1b
agent WebSocket handler + session + challenge-response auth
IbraTech04 May 9, 2026
9bc8186
Updated repositories to PostgreSQL
IbraTech04 May 10, 2026
41db7d5
Finalized STOMP + Websocket + new MusallahBoard Agent protocol.
IbraTech04 May 10, 2026
6458091
updated and normalized entities
IbraTech04 May 10, 2026
90382a4
started moving repos around
IbraTech04 May 10, 2026
e4184a4
This is fun why did I start vibe codign?
IbraTech04 May 10, 2026
f5b611e
Finalized all new models and repositories. Believe it or not, none of…
IbraTech04 May 10, 2026
878efc4
moved files around packages
IbraTech04 May 10, 2026
afcf60d
removed stale test files
IbraTech04 May 10, 2026
8e91e4f
dear god what was I smoking when I first built this
IbraTech04 May 10, 2026
bb58b77
fixes to the stuff I just wrote
IbraTech04 May 10, 2026
604afed
smol refactors
IbraTech04 May 10, 2026
111314b
working towards full rewrite
IbraTech04 May 10, 2026
bc8fe3f
codex plan tentatively being added
IbraTech04 May 10, 2026
d3e7e75
Final auth model changes
IbraTech04 May 12, 2026
525cb20
finalized service and controller rewrites, still needs tests
IbraTech04 May 13, 2026
aeaadd8
fixes to PR Review
IbraTech04 May 13, 2026
9f6e5c9
dockerized for postgresql
IbraTech04 May 13, 2026
a8849ad
fixed viln
IbraTech04 May 13, 2026
17c431e
minor fixes
IbraTech04 May 13, 2026
4a6a5ce
revert: bump jwt utils
IbraTech04 May 13, 2026
36f15e0
updated docker config
IbraTech04 May 14, 2026
5932344
various changes for musallahboard (no i don't care that this isn't th…
IbraTech04 May 15, 2026
355a48e
added test cases
IbraTech04 May 17, 2026
1ea1949
about to check out
IbraTech04 Jun 17, 2026
44f0adc
Stop tracking .claude/worktrees
IbraTech04 Jun 22, 2026
96a190a
massive bugfix + refactor + a whole weeks worth of work I forgot to c…
IbraTech04 Aug 1, 2026
c7f3d65
forgot to commit hehe
IbraTech04 Aug 1, 2026
01d9752
Added OpenAPI Docs + CI for consumers
IbraTech04 Aug 3, 2026
34d696d
Massive changes to support new OpenAPI configurations + new features …
IbraTech04 Aug 3, 2026
18e4925
Updates to board payload
IbraTech04 Aug 3, 2026
98536c3
smol updates
IbraTech04 Aug 5, 2026
281aab1
smol fixes
IbraTech04 Aug 7, 2026
3cb0889
Revamp permissions system
IbraTech04 Aug 8, 2026
d63a0ad
small changes to models
IbraTech04 Aug 8, 2026
761da3e
Add new endpoints for managing device audience and display name
IbraTech04 Aug 10, 2026
384b471
All frames are now backend-managed, minus socials which is coming next
IbraTech04 Aug 10, 2026
e07707b
Scaffolding around arbitrary social media frames
IbraTech04 Aug 10, 2026
fdbc382
Finalized Social Media Frames + flyaway db migrations
IbraTech04 Aug 11, 2026
3a9ed39
Allow empty agenda frames to be sent
IbraTech04 Aug 11, 2026
07176e8
update statics to be consistent with rest of project
IbraTech04 Aug 11, 2026
095c475
Unhook string literals
IbraTech04 Aug 11, 2026
a0e1dec
fix vuln
IbraTech04 Aug 11, 2026
f1b1fc0
fix more vulns
IbraTech04 Aug 11, 2026
731d931
Merge pull request #6 from LensBridge/frame-revamp
IbraTech04 Aug 11, 2026
90190e0
Added frame durations for islamic quotes
IbraTech04 Aug 11, 2026
9da8d9e
mvnw mode fix
IbraTech04 Aug 11, 2026
95d5ae8
update emails
IbraTech04 Aug 11, 2026
ef50c91
update test cases
IbraTech04 Aug 12, 2026
4e57474
Fix some stuff
IbraTech04 Aug 12, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
26 changes: 25 additions & 1 deletion .claude/settings.local.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,31 @@
"Bash(Out-Null)",
"Bash(Write-Output \"done\")",
"Bash(./mvnw.cmd compile *)",
"Bash(git *)"
"Bash(git *)",
"Bash(Get-ChildItem *)",
"Bash(xargs grep -l \"enroll\\\\|heartbeat\")",
"Bash(findstr /C:\"hypersistence\" /C:\"jackson\" /C:\"lombok\" /C:\"java.version\" /C:\"<java>\")",
"Bash(./mvnw -q -DskipTests compile)",
"Bash(./mvnw -q test \"-Dtest=Ed25519VerifierTest+EnrollmentTokenServiceTest\")",
"Bash(./mvnw -q test \"-Dtest=Ed25519VerifierTest,EnrollmentTokenServiceTest\")",
"Bash(./mvnw test *)",
"Bash(findstr /C:\"Tests run\" /C:\"BUILD\")",
"Bash(findstr \"Tests\")",
"Bash(findstr /V \"^??\")",
"Bash(findstr /V \"^[ ]M .claude\")",
"Bash(mvn -q -DskipTests compile)",
"PowerShell(mvn *)",
"PowerShell(.\\\\mvnw.cmd -q -DskipTests compile 2>&1 | Select-Object -Last 100)",
"PowerShell(.\\\\mvnw.cmd -DskipTests compile 2>&1 | Select-Object -Last 60)",
"PowerShell(.\\\\mvnw.cmd -DskipTests clean compile 2>&1 | Select-Object -Last 80)",
"PowerShell(.\\\\mvnw.cmd test-compile 2>&1 | Select-Object -Last 40)",
"Bash(go build *)",
"Bash(go vet *)",
"Bash(wsl *)",
"Bash(Select-Object -First 50)",
"Bash(gh pr *)",
"Read(//tmp/**)",
"Bash(Select-Object Name)"
]
}
}
17 changes: 17 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
target/
.idea/
.vscode/
.git/
.gitignore
.claude/
.mvn/wrapper/maven-wrapper.jar
*.db
*.log
docs/
README.md
Dockerfile
docker-compose.yml
docker/
.env
.env.*
!.env.example
28 changes: 28 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Copy to .env and fill in. .env is gitignored.

# --- Postgres ---
POSTGRES_DB=lensbridge
POSTGRES_USER=lensbridge
POSTGRES_PASSWORD=change-me-strong-password

# --- App secrets ---
# Generate with: openssl rand -base64 32
JWT_SECRET=
ONBOARDING_SECRET=

# --- Cloudflare R2 ---
CLOUDFLARE_R2_ACCESS_KEY_ID=
CLOUDFLARE_R2_SECRET_ACCESS_KEY=
CLOUDFLARE_R2_BUCKET_NAME=lensbridge-media
CLOUDFLARE_R2_PUBLIC_URL=https://media.lensbridge.tech

# --- SMTP (Purelymail) ---
MAIL_USERNAME=noreply@lensbridge.tech
MAIL_PASSWORD=

# --- Allowed CORS origins (full URLs, no trailing slash) ---
FRONTEND_BASEURL=https://lensbridge.tech
MUSALLAHBOARD_BASEURL=https://musallah.lensbridge.tech

# --- API docs (keep false in prod) ---
SPRINGDOC_API_DOCS_ENABLED=false
61 changes: 61 additions & 0 deletions .github/workflows/openapi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
name: OpenAPI contract

# openapi.yaml is the contract three separate repositories generate their clients
# from: LensBridgeFrontend, MusallahBoard (kiosk) and the Go agent. It is committed
# so that a change to a response shape shows up as a reviewable diff -- this job
# exists to make sure the committed copy actually matches the controllers.

on:
push:
branches: [master, develop]
pull_request:
workflow_dispatch:

jobs:
contract:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-java@v4
with:
java-version: '21'
distribution: temurin
cache: maven

- name: Set up Python for the spec quality gate
uses: actions/setup-python@v5
with:
python-version: '3.12'

- run: pip install pyyaml

- name: Run tests
run: ./mvnw --batch-mode test

- name: Regenerate openapi.yaml
# Boots the app on a dedicated port and scrapes /v3/api-docs.yaml.
run: ./mvnw --batch-mode -P openapi verify -DskipTests

- name: Fail if the committed spec is stale
run: |
if ! git diff --exit-code --stat -- openapi.yaml; then
echo "::error::openapi.yaml does not match the controllers."
echo "A contract change was made without regenerating the spec."
echo "Run './mvnw -P openapi verify -DskipTests' and commit openapi.yaml."
git diff -- openapi.yaml
exit 1
fi
echo "openapi.yaml matches the controllers."

- name: Check spec quality
# Untyped responses generate `unknown` in TypeScript and `interface{}` in Go,
# which is indistinguishable from having no contract at all.
run: python tools/check_openapi.py openapi.yaml --strict-ids

- name: Publish the spec for downstream repos
uses: actions/upload-artifact@v4
with:
name: openapi
path: openapi.yaml
if-no-files-found: error
16 changes: 16 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
node_modules
HELP.md
target/
docs/
!.mvn/wrapper/maven-wrapper.jar
!**/src/main/**/target/
!**/src/test/**/target/
Expand All @@ -16,6 +17,11 @@ target/

*.properties

# Test configuration holds no secrets and must be committed: CI checks out a tree with no
# application.properties at all, so without this the test suite runs on the inline @Value
# defaults and behaves differently there than on a developer machine.
!src/test/resources/application.properties

### IntelliJ IDEA ###
.idea
*.iws
Expand All @@ -34,3 +40,13 @@ build/

### VS Code ###
.vscode/

lensbridge-dev.db

# Docker
.env
.env.*
!.env.example
docker/nginx/certs/*
!docker/nginx/certs/.gitkeep
.claude/worktrees/*
20 changes: 20 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# syntax=docker/dockerfile:1.7

FROM maven:3.9-eclipse-temurin-21 AS build
WORKDIR /build
COPY pom.xml ./
RUN mvn -B -e -ntp dependency:go-offline
COPY src ./src
RUN mvn -B -e -ntp -DskipTests package \
&& cp target/*.jar /build/app.jar

FROM eclipse-temurin:21-jre-jammy
WORKDIR /app
RUN useradd -r -u 1001 -g root lensbridge \
&& mkdir -p /app/thumbnails \
&& chown -R lensbridge:root /app
COPY --from=build /build/app.jar /app/app.jar
USER lensbridge
EXPOSE 8080
ENV JAVA_OPTS="-XX:MaxRAMPercentage=75.0"
ENTRYPOINT ["sh","-c","exec java $JAVA_OPTS -jar /app/app.jar"]
115 changes: 35 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,107 +2,44 @@

# LensBridge Backend

![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.5.2-blue)
![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.5.14-blue)
![Java](https://img.shields.io/badge/Java-21-orange)
![Maven](https://img.shields.io/badge/Maven-3.3.2-red)
![MongoDB](https://img.shields.io/badge/MongoDB-4.4-green)
![PostgreSQL](https://img.shields.io/badge/PostgreSQL-16-blue)

</p>

> A backend service for LensBridge, a platform for managing crowdsourced event photos and videos.
> A backend service for LensBridge, a platform for managing crowdsourced boardEvent photos and videos.

LensBridge is the all-in-one solution for universities to manage and showcase event photos and videos. This backend service provides APIs for user management, event management, and upload management.

## Features

- **User Management**: Register, login, and manage user profiles. All authentication is handled via JWT.
- **Event Management**: Create, update, and delete events. Uploads are associated with events for ease of organization.
- **Upload Management**: Upload photos and videos, with options for approval, featuring, and anonymization.
- **Admin Operations**: Admins can manage uploads, events, and user roles with enhanced endpoints for better user information.

## General Information

This project is built using Java (duh), Spring Boot, and MongoDB. It follows the MVC architecture and uses JWT for secure authentication. The API is designed to be RESTful, providing a clean and intuitive interface for frontend applications.
LensBridge is the _ultimate_ platform for collecting and sharing photos from events. Whether you're organizing a conference, a concert, or a community gathering, LensBridge makes it easy to gather and showcase photos from attendees. This backend service provides the core functionality for user management, event management, and upload handling, all while ensuring security and scalability.

## Getting Started

### Prerequisites

- Java 21 or higher
- Maven 3.3.2 or higher (Or use the wrapper)
- Some form of MongoDB and Cloudflare R2 access
- Some form of SQL distribution (PostgreSQL, MySQL, etc.) - I use PostgreSQL in prod and SQLite for local development.
- Cloudflare R2 (Or any S3-compatible storage service) for file storage
- (Optional) SMTP server for email notifications

### Setup
### Setup - Local Development

1. Clone the repository:

```bash
git clone https://github.com/LensBridge/LensBridgeBackend.git
```

2. Create the `application.properties` file in `src/main/resources/` with the following content:
2. Create the `application.properties` file:

```
# Server configuration
server.port=8080
# Note: Uncomment the following lines to enable SSL (for production use)
#server.ssl.enabled=
#server.ssl.key-store=
#server.ssl.key-store-type=
#server.ssl.key-store-password=
#server.ssl.key-alias=
#server.address=0.0.0.0

# Database configuration - MongoDB
spring.data.mongodb.uri=
spring.data.mongodb.database=

# For CORS - Fill in with the frontend URL.
frontend.baseurl=

# Cloudflare R2 configuration
cloudflare.r2.access-key-id=your-access-key-id
cloudflare.r2.secret-access-key=your-secret-access-key
cloudflare.r2.endpoint=https://your-account-id.r2.cloudflarestorage.com
cloudflare.r2.bucket-name=your-bucket-name
cloudflare.r2.public-url=https://your-account-id.r2.cloudflarestorage.com/your-bucket-name

# Uploads Config
uploads.video.maxduration=240
uploads.max-size=1000000000
uploads.allowed-file-types=video/mp4,video/quicktime,video/x-matroska,video/x-msvideo,image/jpeg,image/png,image/heic
# Rate limiting configuration
ratelimit.requests=100
ratelimit.duration.minutes=1

# File upload configuration
spring.servlet.multipart.max-file-size=100MB
spring.servlet.multipart.max-request-size=150MB

# Logging configuration
logging.level.com.ibrasoft.lensbridge=INFO
logging.level.org.springframework.security=DEBUG
logging.level.org.springframework.mail=DEBUG
logging.level.org.springframework.mail.javamail=DEBUG

# SMTP Configuration for email notifications
spring.mail.host=
spring.mail.port=
spring.mail.username=
spring.mail.password=
spring.mail.properties.mail.smtp.auth=
spring.mail.properties.mail.smtp.ssl.enable=
spring.mail.properties.mail.smtp.ssl.trust=
spring.mail.properties.mail.smtp.connectiontimeout=
spring.mail.properties.mail.smtp.timeout=10000
spring.mail.properties.mail.smtp.writetimeout
spring.mail.properties.mail.debug=
spring.mail.from=
spring.mail.from.name=

lensbridge.app.jwtSecret=
lensbridge.app.jwtExpirationMs=
```
```bash
cp src/main/resources/application.properties.example src/main/resources/application.properties
```

Then edit `application.properties` to configure your database connection, R2 credentials, and other settings.

> I suggest using SQlite for local development to avoid the overhead of setting up a full database. Just change the datasource URL to `jdbc:sqlite:lensbridge.db` and remove the username/password. The dependency is already included in the project.

3. Build the project using Maven:

Expand All @@ -120,6 +57,24 @@ lensbridge.app.jwtExpirationMs=

And that's it! You now have a running instance of the LensBridge backend. Pair this with the frontend application to create a complete LensBridge experience.

## Deployment

This project utilizes Docker for containerization, making it easy to deploy on any platform that supports Docker (AWS, Heroku, DigitalOcean, etc.). A `Dockerfile` is included in the repository. To build and run the Docker container, use the following commands:

```bash
docker compose up --build
```

...aaaand that's it. Pretty anti-climactic. Make sure to include your SSL certs in the `docker/nginx/certs` directory and configure the environment variables accordingly. Once the container is running, the API will be accessible at `https://localhost/api/`.

## API Documentation

*Coming soon*
This project uses SpringDoc OpenAPI to generate API documentation. Once the application is running, you can access the API docs at:

```
http://localhost:8080/swagger-ui.html
```

Consider disabling this in production. This _is_ an open source project, though; Not sure how effective that would be.

A local copy of the API documentation will be added sometime in the distant future
Loading
Loading