Skip to content

Minbar v2027 - #17

Merged
IbraTech04 merged 54 commits into
masterfrom
develop
Sep 17, 2026
Merged

IbraTech04 merged 54 commits into
masterfrom
develop

Conversation

@IbraTech04

Copy link
Copy Markdown
Collaborator

This PR serves as the initial version for Minbar v2027, supporting MusallahBoard as a first-class product and working towards deprecating LensBridge's existing API.

Eventually, the rest of Minbar's features (mobile app, etc) will be merged in (from branch minbar-features), however those still need more testing + cleaning up, so those will follow

IbraTech04 and others added 30 commits May 8, 2026 16:47
…s, controllers

Converts all MusallahBoard domain models from MongoDB to JPA entities,
creates JPA repositories under repository/sql/, rewrites BoardService
and PosterService for JPA, updates transformers, assembler, controllers.
Applies all model normalization fixes from PLAN.md section 0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- All 6 board domain models converted from MongoDB to JPA entities
- New JPA repositories under repository/sql/
- BoardService rewritten for JPA; PosterService repo swap
- WeeklyContent redesigned: UUID PK, year/weekNumber, @onetomany children
- IslamicQuote and JummahPrayer promoted to owned @entity rows
- CalculationMethod enum replaces raw int method in Location
- All model cleanup items A-E from PLAN.md applied
- EventView extracted to top-level DTO, frame config coupling resolved
- AuditEvent.timestamp fixed to Instant
- pom.xml: spring-boot-starter-data-jpa + postgresql driver added
- @EnableJpaRepositories wired in LensBridgeApplication

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…Ed25519

Adds the persistence layer and onboarding handshake for the new agent
control plane that lets the admin dashboard run commands on each Pi.

Layer 1 - entities + repos:
- Device extended with publicKey, agentVersion, hardwareModel,
  lastSeenIp, revokedAt
- EnrollmentToken: one-time admin-issued pairing token, SHA-256 hash
  stored, plaintext shown once
- DeviceTelemetry: append-only heartbeat history
- DeviceCommand + DeviceCommandStatus: audit log + delivery queue with
  state machine (PENDING -> DELIVERED -> ACKED -> RUNNING -> terminal)
- DeviceRepository.findByRevokedAtIsNullAndLastHeartbeatBefore for
  offline detection

Layer 2 - Ed25519 + enrollment:
- Ed25519Verifier wraps JDK 17+ native Ed25519; raw 32-byte public
  keys wrapped to X.509 SubjectPublicKeyInfo at verify time
- EnrollmentTokenService issues 144-bit base64 tokens, atomic
  single-consume with expiry check, optional pepper
- DeviceEnrollmentService orchestrates token consume + Device row
  creation with public key
- POST /api/agent/enroll (public, token-authenticated) for agent
  side; admin endpoints under /api/admin/board/devices for token
  issuance, list, revoke
- WebSecurityConfig permits /api/agent/enroll
- 12 unit tests (Ed25519 round-trip + tamper + wrong-key + bad-input;
  token issue + consume happy/expired/used/unknown/blank)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Wraps up the PostgreSQL/normalization migration started in the prior
two commits by deleting now-dead types and tightening DTOs/services
around the Device-as-aggregate-root model.

- Remove BoardLocation enum, StringToBoardLocationConverter, and the
  legacy Mongo-shaped BoardConfigRepository under repository/ in
  favour of the embedded Location + DeviceConfig under board/embedded
- Rename BoardConfig.java -> board/embedded/DeviceConfig.java
- Slim DTOs (Create/UpdatePosterRequest, Create/UpdateCalendarEventRequest,
  EventView, MusallahBoardPayload) - drop fields that no longer map to
  the JPA entities
- BoardAdminController, MusallahBoardController: route everything
  through deviceId; drop boardLocation path params
- BoardService, PosterService, BoardContext, BoardPayloadAssembler,
  DailyScheduleFrameTransformer, EventListFrameTransformer: align
  with the device-keyed lookup
- Update docs/MUSALLAH_BOARD_API.md and add docs/musallahboard-api.md

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Copilot <copilot@github.com>
@IbraTech04
IbraTech04 merged commit e0ecef7 into master Sep 17, 2026
0 of 2 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e57474d95

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread docker-compose.yml
Comment on lines +30 to +35
SPRING_PROFILES_ACTIVE: prod
POSTGRES_HOST: postgres
POSTGRES_PORT: "5432"
POSTGRES_DB: ${POSTGRES_DB}
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add runnable dev and prod configuration

There is no tracked application-dev.properties or application-prod.properties; the only main resource is application.properties.example, which Spring does not load. This Compose service selects prod but supplies POSTGRES_* variables rather than a spring.datasource.url (or SPRING_DATASOURCE_URL), so DataSource auto-configuration fails before the health check. The same missing dev configuration also makes the inspected OpenAPI workflow's -P openapi boot step fail, since it explicitly starts the dev profile while required datasource, JWT, R2, and CORS properties have no values.

Useful? React with 👍 / 👎.

# Flyway's classpath scan doesn't restrict to the resolved subdirectory -- it scans both
# db/migration/sqlite and db/migration/postgresql and fails startup with "Found more than
# one migration with version 1". Confirmed against prod on 2026-08-10; see docs/MIGRATIONS.md.
# spring.flyway.locations=classpath:db/migration/postgresql

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Select one migration directory in the sample config

Following the README's documented copy step leaves this setting commented out, so Flyway falls back to classpath:db/migration and discovers both the SQLite and PostgreSQL V1__initial_schema.sql files. Since both have version 1, startup aborts with Flyway's duplicate-migration-version error; set the SQLite location in the base dev sample or provide the promised per-profile settings.

Useful? React with 👍 / 👎.

Comment on lines +76 to +83
EnrollmentToken row = found.get();
Instant now = Instant.now();
if (row.getConsumedAt() != null) return Optional.empty();
if (row.getExpiresAt().isBefore(now)) return Optional.empty();

row.setConsumedAt(now);
row.setConsumedByDeviceId(consumedByDeviceId);
return Optional.of(repository.save(row));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Claim enrollment tokens atomically

When two agents submit the same valid token concurrently, each transaction can read consumedAt == null before either update commits. On PostgreSQL, the second update waits for the first and then still overwrites the row because there is no lock, version column, or conditional UPDATE ... WHERE consumed_at IS NULL; both calls return a token and proceed to create devices. Use a pessimistic lock or a conditional update whose affected-row count is checked before enrollment.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant