Repository navigation
Feature/documentation central - #30
Merged
Merged
Conversation
…config Four additions, plus two fixes that were required to make them work. Documentation site (documentation-central/) - Docusaurus 3.10 + TypeScript + Mermaid, 18 pages: getting started, API reference, architecture, data model, testing, known issues - Endpoint reference derived from the controllers, not the old README, which advertised a /api prefix the code has never had - onBrokenLinks: throw, so a dead cross-reference fails the build - vercel.json for deployment with Root Directory = documentation-central Swagger UI / OpenAPI (springdoc 2.8.6) - OpenApiConfig with a bearer-JWT scheme so Authorize works in the UI - @tag / @operation / @apiresponse on every controller, @Schema on request DTOs, @hidden on the three smoke-test controllers - Swagger routes allow-listed in SecurityConfiguration Mockito test suite (139 tests, no database required) - 80 service unit tests, 59 @WebMvcTest controller slices - New ./gradlew unitTest task excluding the Postgres-dependent ConnectlyApiApplicationTests; JaCoCo wired up - Shared @ControllerSliceTest annotation; @MockitoBean throughout, since Boot 3.4 deprecated @MockBean Environment configuration - .env.example documenting every setting - application.properties now reads ${VAR:default} throughout, loaded via spring.config.import=optional:file:.env[.properties] -- no dotenv library - A fresh clone still runs with no .env at all - .env gitignored; removed the unused dotenv-java dependency Fixes required along the way - PostLikeController mapped /{postId}/{postId}/likes/toggle, which Spring Boot 3's PathPatternParser rejects -- the application could not start at all. Now /{postId}/likes/toggle, with a regression test. - GlobalExceptionHandler's catch-all claimed MethodArgumentNotValidException before Spring could map it, so every malformed request body returned 500. Added an explicit handler returning 400 with the offending fields. Also corrected the .http request templates and the README endpoint list, both of which pointed at the non-existent /api prefix.
…tion Every fix here was verified against a running instance, not just unit tests. Security - Responses no longer leak the BCrypt hash or the verification token. Registration, GET /users/me, the user listings and every embedded comment author now return UserResponseDto. The verification token was the worse half: anyone seeing a registration response could activate the account without the mailbox. - Registration grants ROLE_USER. It used to leave roles empty, so every account had zero authorities and /user/**, /admin/** and all three @PreAuthorize endpoints were unreachable by anyone. - Registration enforces the same password strength rules as reset, so an account can no longer be created with a password its owner could never reset back to. - CORS is actually applied. Two configurations existed and neither took effect, because the filter chain never called .cors(...) -- no browser frontend on another origin could reach the API. One config now, driven by CORS_ALLOWED_ORIGINS. - bump.yml reads ${{ secrets.BUMP_TOKEN }} instead of a literal token. The old value is still in git history and needs rotating. Correctness - /auth/registrationConfirm accepts the token users are actually sent. Registration produced two unrelated UUIDs -- one emailed, one written to the verification_token table by RegistrationListener -- and the confirm endpoint only accepted the second. The listener now reuses the emailed token, and no longer sends a duplicate registration email carrying a dead link. Both endpoints check expiry. - Deleted accounts with content are purged. Every FK to app_user was NO ACTION, so deleting a user with a single post, comment or like threw a constraint violation that ScheduledDeletionTask swallowed -- the account stayed soft-deleted forever after its owner was told the data would be gone in 30 days. permanentlyDeleteUser now clears dependants in order, and the migration declares ON DELETE CASCADE. - The admin endpoints can see the accounts they manage. Both resolved users through an active-only lookup, so force-delete answered 404 for exactly the soft-deleted accounts it existed to purge, and extend-deletion could never reach its "not scheduled for deletion" branch. - getComment validates its {postId}. /posts/999/comments/1 used to return a comment belonging to post 10. - PostService.deletePost compared a Set<Role> against the string "ADMIN", which is never true, so the admin arm of the check was dead code. Status codes - 401 for missing/invalid tokens, 403 for authenticated-but-forbidden, via JwtAuthenticationEntryPoint and JwtAccessDeniedHandler. This was inverted. - Unknown URLs 404, wrong verbs 405, unparseable bodies 400. The catch-all handler was swallowing Spring's own statuses and reporting 500. - PUT /posts/{id} on a missing post is 404; duplicate email or username at registration is 409. Both were 500. Schema - Flyway owns the schema (V1__baseline_schema.sql), replacing schema.sql, which spring.sql.init.mode=never meant never ran and which had drifted. - ddl-auto defaults to validate rather than create-drop, so a restart no longer drops every table. Validation immediately caught VerificationToken using GenerationType.AUTO where every other entity uses IDENTITY. Scheduling - ShedLock on both jobs, so replicas no longer each run the 02:00 deletion sweep. - VerificationTokenService.cleanupExpiredTokens() is finally called; it had no @scheduled annotation, so expired tokens accumulated forever. Also removed the stale "http-template copy" directory, updated the docs site to match every change, and regenerated doc/api-documentation.yml. Tests: 143, all green, no database required.
README
- Centered shields.io badge row: Java, Spring Boot, PostgreSQL, Gradle, JWT,
Flyway, Swagger, Docusaurus, test count, endpoint count, licence
- Blockquote tagline, horizontal rules, tech-stack table
- Endpoints as per-area tables rather than bullet lists
- Annotated project tree
- Collapsible <details> blocks for sample requests and responses
- Constraints, acknowledgments and licence sections
New docs page: api/postman.md
- Import the live spec by link (http://localhost:8080/v3/api-docs) so the
collection stays in sync with the code; the checked-in
doc/api-documentation.yml as the offline fallback
- Collection-level bearer auth with a {{jwt}} variable, and a login
post-response script that captures the token automatically
- A first-run request order, environments for multiple targets, Newman and
REST Client alternatives, and troubleshooting
- Linked from the sidebar, the Swagger page, the intro and the README
Also corrected a stale line in api/swagger.md: an expired token now answers
401, not 403.
The workflow deployed doc/api-documentation.yml to Bump.sh on every push to main and commented API diffs on pull requests. Removing it drops the external dependency and the credential it needed. - Deleted .github/workflows/bump.yml (the only workflow in the repo) - doc/api-documentation.yml stays: it is still the offline fallback for a Postman import, and the docs describe it as a snapshot rather than a CI-published artifact - Reworded the Known Issues entry -- the file is gone, but the token it once carried in plaintext is still in earlier commits and needs revoking in the Bump.sh dashboard rather than scrubbing from history - Dropped Bump.sh from the tooling list and the README project tree
One canonical template at .github/pull_request_template.md, so PR descriptions stop being written from scratch each time. Structure follows the usual Summary / Changes / Testing / Screenshots / Database Changes / Breaking Changes / Deployment Notes, with the prompts pointed at this repo's actual hazards rather than generic ones: - Testing lists ./gradlew unitTest, ./gradlew test and the Docusaurus build. It states plainly that there is NO CI here -- the last workflow went with the Bump.sh removal -- so an unchecked box is a real gap, not a formality. - Database Changes covers the Flyway rules that actually bite: V-number collisions between parallel branches, never editing an applied migration, ddl-auto=validate meaning entities and migrations must agree exactly, FKs to app_user needing ON DELETE CASCADE, and listings honouring soft delete. - Breaking Changes calls out that status codes count -- the deliberate 401/403 split and the 403 on a missing post look like bugs and are not. - Deployment Notes covers the Vercel root directory, adding new config to both .env.example and application.properties, overriding the public JWT_SECRET default, and hand-refreshing doc/api-documentation.yml now that nothing regenerates it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a documentation site, an interactive API console, a test suite, and environment-based configuration to a repository that previously had none of the four. The endpoint reference is derived from the controllers rather than the old README, which advertised an
/apiprefix the code has never had.Two fixes are bundled here because the rest of the PR could not be verified without them: the application could not start at all on
main, and every malformed request body returned 500.Stacked PR 1 of 3. Merge before
fix/known-issues.Changes
Features
documentation-central/— Docusaurus 3.10 site (TypeScript, Mermaid), 18 pages: getting started, API reference, architecture, data model, testing, known issues.onBrokenLinks: 'throw', so a dead cross-reference fails the build./swagger-ui.htmland/v3/api-docs, with a bearer-JWT scheme so Authorize works.@Tag/@Operation/@ApiResponseon every controller,@Schemaon request DTOs,@Hiddenon the three smoke-test controllers.@WebMvcTestcontroller slices. New./gradlew unitTesttask excludes the Postgres-dependentConnectlyApiApplicationTests; JaCoCo wired up..env.exampledocumenting every setting.application.propertiesnow reads${VAR:default}throughout, loaded viaspring.config.import=optional:file:.env[.properties]. A fresh clone still runs with no.envat all.Fixes
PostLikeControllermapped/{postId}/{postId}/likes/toggle. Spring Boot 3'sPathPatternParserrejects capturing the same variable twice, so the context aborted and no endpoint served any request. Now/{postId}/likes/toggle, with a regression test that fails at context load if a duplicate segment returns.GlobalExceptionHandler's catch-all claimedMethodArgumentNotValidExceptionbefore Spring could map it, so every malformed body returned 500. An explicit handler now returns 400 listing the offending fields.Chores
.httptemplates and the README endpoint list, both of which pointed at the non-existent/apiprefix.dotenv-javadependency — Spring reads.envnatively.Testing
./gradlew unitTest— 139 tests, 0 failures, no database requiredcd documentation-central && npm run build && npm run typecheck— both cleanPostLikeControllerfix (Invalid mapping pattern detected) and starts cleanly after./gradlew bootRun→ Swagger UI serves at/swagger-ui.html(302 →/swagger-ui/index.html, 200),/v3/api-docsreturns 24 paths, the three@Hiddendemo endpoints are excludedGET /users/me→POST /posts(201) →POST /posts/{id}/comments(201) → like toggle returningtruethenfalseMAIL_PORT=1026 ./gradlew bootRun— confirmed the env-override path works end to endNot applicable: no frontend, no Playwright, no Maven (this repo is Gradle).
Screenshots
N/A — no UI changes. The docs site renders locally via
npm start.Database Changes
None. Schema handling is unchanged in this PR (still Hibernate
create-drop); Flyway arrives in PR 2.Breaking Changes
One, and it is a repair rather than a regression: the like-toggle route moves from
/{postId}/{postId}/likes/toggleto/{postId}/likes/toggle. No client can be depending on the old path — the application could never start with it, so the endpoint has never served a request.Validation failures change from 500 to 400. Any client branching on 500 for bad input should be updated, though that behaviour was clearly unintended.
Deployment Notes
documentation-central.vercel.jsonalready pins the build command and output directory. Updateurlindocusaurus.config.tsonce the real domain is known — only the sitemap and social-card metadata depend on it.doc/api-documentation.yml(which.github/workflows/bump.ymldeploys) is still missing at this commit — it lands in PR 2.