feat: documentation module#123
Conversation
WalkthroughIntroduces a new documentation module with versioned markdown rendering, navigation, and API integration. Adds DocsController, Documentation service, CommonMark converters and extension, Blade view components and theme, routes and configuration, Scramble API integration, Torchlight and Flux tooling, sample docs for 3.x, and updates project dependencies and build inputs. Changes
Sequence DiagramsequenceDiagram
participant User
participant Route
participant DocsController
participant Documentation
participant Cache
participant FileSystem
User->>Route: GET /docs/{version}/{page}
Route->>DocsController: show(version, page)
alt Invalid Version
DocsController->>DocsController: isVersion() fails
DocsController-->>User: 301 Redirect to default /docs/{default_version}
else Valid Version
DocsController->>Documentation: get(version, page)
Documentation->>Cache: attempt fetch
alt Cache Hit
Cache-->>Documentation: return cached payload
else Cache Miss
Documentation->>FileSystem: read markdown file(s)
Documentation->>Documentation: convert to HTML + TOC (CommonMark + extensions)
Documentation->>Cache: store rendered payload
end
Documentation-->>DocsController: page payload
alt Page Not Found
DocsController-->>User: 404 with attempted versions list
else Page Found
DocsController->>Documentation: getPages(version) for sidebar
DocsController-->>User: Render docs view (layout + theme + TOC)
end
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Tip 📝 Customizable high-level summaries are now available in beta!You can now customize how CodeRabbit generates the high-level summary in your pull requests — including its content, structure, tone, and formatting.
Example instruction:
Note: This feature is currently in beta for Pro-tier users, and pricing will be announced later. Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (8)
resources/docs/3.x/installation.md (1)
1-7: LGTM! Complete the placeholder content.The markdown structure and named anchor are correctly implemented. The placeholder text "Some text" should be replaced with actual installation documentation content.
Do you want me to help draft installation documentation content, or would you like to track this as a separate task?
resources/docs/3.x/releases.md (1)
1-7: Placeholder documentation page.This release notes page is a stub with no content under the Versioning Scheme section. Ensure this is populated before the documentation goes live.
Would you like me to help draft initial content for the release notes or versioning scheme section?
app-modules/docs/routes/docs-routes.php (1)
8-10: Consider using configuration instead of a global constant.Defining
DEFAULT_VERSIONas a global constant can lead to maintainability issues if the value needs to be defined elsewhere or changed based on environment. The docs configuration file (app-modules/docs/config/docs.php) already defines adefault_versionkey.Consider removing this conditional define and accessing the default version via
config('docs.default_version')where needed, ensuring a single source of truth.app-modules/docs/resources/views/components/layout/guest.blade.php (1)
15-15: Consider self-hosting fonts or adding SRI for external resources.Loading fonts from an external CDN (fonts.bunny.net) introduces a dependency on a third-party service and potential privacy considerations. For better performance and control, consider self-hosting the Nunito font family or at minimum adding Subresource Integrity (SRI) attributes to verify resource integrity.
app-modules/docs/src/DocsServiceProvider.php (1)
18-21: Consider using configuration for API version.The version '3.x' is hardcoded in three places (lines 18, 20, 21), but the docs configuration file defines a
default_version. Using the config value would provide a single source of truth and make it easier to update or support multiple API versions.Consider refactoring to:
- Scramble::registerApi('3.x'); + $version = config('docs.default_version'); + Scramble::registerApi($version); - Scramble::registerUiRoute(path: 'docs/3.x/api', api: '3.x'); - Scramble::registerJsonSpecificationRoute(path: 'docs/3.x/swagger.json', api: '3.x'); + Scramble::registerUiRoute(path: "docs/{$version}/api", api: $version); + Scramble::registerJsonSpecificationRoute(path: "docs/{$version}/swagger.json", api: $version);app-modules/docs/resources/views/home.blade.php (1)
71-73: Consider internationalizing hardcoded text.The text "Nesta página" is hardcoded in Portuguese. If the documentation system is intended to support multiple languages, consider using Laravel's localization features.
For example:
- <h3 class="mb-4 text-xs font-bold tracking-wider text-zinc-500 uppercase dark:text-zinc-400"> - Nesta página - </h3> + <h3 class="mb-4 text-xs font-bold tracking-wider text-zinc-500 uppercase dark:text-zinc-400"> + {{ __('docs.on_this_page') }} + </h3>app-modules/docs/src/DocsController.php (1)
35-58: Avoid re‑injectingDocumentationinindexandsidebarYou already have
Documentationinjected via the constructor as$this->docs, so the extraDocumentation $docsparameter is redundant and slightly confusing. You can simplify the signatures and always use the property:- public function index($version, Documentation $docs) + public function index(string $version) { - if (! $this->isVersion($version)) { + if (! $this->isVersion($version)) { return redirect('docs/'.DEFAULT_VERSION.'/index.json', 301); } - return response()->json($docs->indexArray($version)); + return response()->json($this->docs->indexArray($version)); } - public function sidebar($version, Documentation $docs) + public function sidebar(string $version) { if (! $this->isVersion($version)) { return redirect('docs/'.DEFAULT_VERSION.'/sidebar.json', 301); } - return response()->json($docs->getPages($version)); + return response()->json($this->docs->getPages($version)); }app-modules/docs/src/Documentation.php (1)
103-123: Guard against pages without a top‑level#heading inindexArray
preg_matchmay fail to find a#heading, but the code unconditionally indexes$page['title'], which will trigger an undefined index notice (and can break JSON output in strict environments) if a page ever omits that heading:preg_match('/\# (?<title>[^\n]+)/', $contents, $page); // ... 'title' => $page['title'],Consider handling the “no match” case explicitly, e.g. skip such pages or provide a safe fallback:
- preg_match('/\# (?<title>[^\n]+)/', $contents, $page); + preg_match('/\# (?<title>[^\n]+)/', $contents, $page); + if (! isset($page['title'])) { + return []; + }(or whatever fallback strategy you prefer).
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
composer.lockis excluded by!**/*.lockpackage-lock.jsonis excluded by!**/package-lock.jsonpublic/favicon.icois excluded by!**/*.icopublic/images/logo-foda.svgis excluded by!**/*.svgpublic/images/logo.pngis excluded by!**/*.png
📒 Files selected for processing (22)
app-modules/docs/composer.json(1 hunks)app-modules/docs/config/docs.php(1 hunks)app-modules/docs/resources/css/theme.css(1 hunks)app-modules/docs/resources/views/components/layout/guest.blade.php(1 hunks)app-modules/docs/resources/views/home.blade.php(1 hunks)app-modules/docs/routes/docs-routes.php(1 hunks)app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownConverter.php(1 hunks)app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownExtension.php(1 hunks)app-modules/docs/src/DocsController.php(1 hunks)app-modules/docs/src/DocsServiceProvider.php(1 hunks)app-modules/docs/src/Documentation.php(1 hunks)app-modules/he4rt/resources/css/index.css(1 hunks)composer.json(2 hunks)config/cache.php(3 hunks)config/database.php(5 hunks)config/scramble.php(1 hunks)database/seeders/BaseSeeder.php(1 hunks)package.json(1 hunks)resources/docs/3.x/documentation.md(1 hunks)resources/docs/3.x/installation.md(1 hunks)resources/docs/3.x/releases.md(1 hunks)vite.config.js(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownExtension.php (1)
app-modules/docs/src/DocsServiceProvider.php (1)
register(12-12)
database/seeders/BaseSeeder.php (1)
app-modules/tenant/database/factories/TenantFactory.php (1)
withDiscordProvider(32-35)
app-modules/docs/routes/docs-routes.php (2)
app-modules/docs/src/DocsController.php (1)
DocsController(15-121)app-modules/docs/src/Documentation.php (1)
get(71-89)
app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownConverter.php (1)
app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownExtension.php (1)
GithubFlavoredMarkdownExtension(15-25)
app-modules/docs/src/Documentation.php (2)
app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownConverter.php (2)
GithubFlavoredMarkdownConverter(18-41)__construct(25-33)app-modules/docs/src/DocsController.php (2)
__construct(17-17)sidebar(51-58)
🪛 Biome (2.1.2)
app-modules/docs/resources/css/theme.css
[error] 1-1: expected , but instead found (
Remove (
(parse)
[error] 1-1: Don't use unknown media feature names.
Unexpected unknown media feature name.
You should use media feature names defined in the CSS Specifications.
(lint/correctness/noUnknownMediaFeatureName)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Perform Pest Tests / Run
- GitHub Check: Perform Rector Check / Run
🔇 Additional comments (20)
database/seeders/BaseSeeder.php (1)
43-43: Verify the hardcoded Discord provider ID.The Discord provider ID '1442327864052547656' appears to be a Discord snowflake ID. Please confirm whether this is a test/development ID or references a real production Discord server. If this is a production ID, consider moving it to environment configuration or using a consistent test value to avoid exposing production resource identifiers in source control.
config/database.php (4)
45-45: LGTM: SQLite transaction mode.Setting
transaction_modetoDEFERREDis explicit but matches SQLite's default behavior, so this won't change functionality.
177-180: LGTM: Redis cache connection retry settings.The retry configuration mirrors the default connection settings, providing consistent resilience behavior across Redis connections.
70-78: The review comment is incorrect and should be ignored.The review claims a breaking change from
DB_MARIA_*toDB_*environment variables, but verification shows:
- No
DB_MARIA_*references exist anywhere in the codebase or .env files- The MariaDB connection configuration (lines 68–86) uses only generic
DB_*variables- Both
.env.exampleand.env.testing.exampledocument onlyDB_*variables- Git history confirms the MariaDB connection has always used
DB_*variables (commit ecb8bcb shows identical pattern)The code at lines 70–78 is correct and requires no changes to environment variable names. There is no breaking change to document or migrate.
Likely an incorrect or invalid review comment.
164-167: Redis retry configuration is supported.These options were introduced in Laravel 11, and the codebase targets Laravel ^12.39.0, which is a newer version. The configuration is valid and properly supported.
config/cache.php (1)
96-102: The failover cache driver is supported in your Laravel version.The failover cache driver was introduced in Laravel 12 (12.35.0 release), and your project requires Laravel ^12.39.0, which includes full support for this driver. No action is needed.
app-modules/he4rt/resources/css/index.css (1)
23-23: LGTM!The new @source directive correctly expands the Tailwind CSS compilation scope to include Blade views from all app-modules, ensuring that the documentation module's views are properly styled.
resources/docs/3.x/documentation.md (1)
1-3: LGTM!The documentation index structure is clear and uses the {{version}} placeholder correctly for versioned navigation. The minimal structure provides a good foundation for the documentation system.
app-modules/docs/config/docs.php (1)
1-7: LGTM!The configuration file correctly sets the default documentation version to '3.x', which aligns with the Scramble configuration and the documentation structure. The use of strict types is a good practice.
package.json (1)
19-19: I'll check for known vulnerabilities in this version:Let me search more specifically for the typography plugin:
Let me search for the direct dependencies of the typography package:
Version is current with no known vulnerabilities.
@tailwindcss/typography 0.5.19 is the latest version and has only 1 direct dependency. No security vulnerabilities were found for this package version. The caret constraint (^0.5.19) is appropriate and will allow compatible minor and patch updates.
config/scramble.php (1)
1-138: RestrictedDocsAccess middleware is properly configured.The middleware is correctly imported and registered as a default Dedoc Scramble middleware to restrict access to API docs. The middleware array configuration shown (with 'web' and RestrictedDocsAccess::class) matches the default Scramble setup. The implementation is valid and follows documented best practices.
vite.config.js (1)
15-15: LGTM!The addition of the docs theme CSS to the Vite build inputs follows the existing pattern and correctly integrates the new documentation module's styling.
app-modules/docs/routes/docs-routes.php (1)
12-15: LGTM!The route definitions follow Laravel conventions and provide appropriate endpoints for the documentation module.
app-modules/docs/resources/views/components/layout/guest.blade.php (1)
1-25: LGTM!The guest layout component follows Blade conventions and integrates cleanly with the Flux UI framework and Vite asset pipeline.
app-modules/docs/resources/css/theme.css (2)
7-47: LGTM!The color scheme definitions using OKLCH values are well-structured and provide comprehensive light and dark mode support. The mapping from
--gray-*to--color-zinc-*maintains flexibility in the design system.
1-5: The Tailwind CSS v4 syntax is valid and compatible with the project.The project uses Tailwind CSS v4.1.17 (from package.json devDependencies), and the @import "tailwindcss" source() syntax is supported in Tailwind CSS v4. The directives
@import 'tailwindcss' source(none)and@pluginin the file are correct for this version. The syntax errors flagged by Biome reflect its current lack of support for Tailwind v4 syntax, not an actual issue with the code.app-modules/docs/src/DocsServiceProvider.php (1)
14-22: LGTM!The service provider correctly merges configuration and registers the Scramble API documentation endpoints.
app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownExtension.php (1)
15-24: LGTM!The extension correctly implements the CommonMark
ExtensionInterfaceand registers the appropriate GitHub Flavored Markdown extensions plus the Blade extension for template integration.app-modules/docs/resources/views/home.blade.php (1)
43-93: LGTM!The Alpine.js implementation for the Table of Contents is well-structured, using IntersectionObserver for active heading tracking and providing smooth scrolling navigation. The responsive design appropriately hides the TOC on smaller screens.
app-modules/docs/src/CommonMark/Markdown/GithubFlavoredMarkdownConverter.php (1)
18-40: GFM converter implementation looks solidThe converter cleanly encapsulates environment setup and exposes the environment when needed; no issues from my side.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
composer.json (1)
39-39: Fix unresolvable livewire/flux version constraint.Line 39 declares
"livewire/flux": "^2.7.1", but the latest available version is v2.6.1. The caret constraint^2.7.1requires at least v2.7.1, which doesn't exist. This will causecomposer installto fail.Change the constraint to a resolvable version such as
^2.6or^2.0.Apply this diff:
- "livewire/flux": "^2.7.1", + "livewire/flux": "^2.6",
🧹 Nitpick comments (5)
composer.json (2)
15-15: Verify exact version pin for symfony/browser-kit.Line 15 pins symfony/browser-kit to an exact version
v7.0.8. Consider using a version constraint like^7.0.8instead of an exact pin to allow for patch updates and reduce maintenance burden. Exact version pins should be reserved for production lock files (composer.lock), not source code constraints.
20-20: Tighten version constraint for he4rt/docs.Line 20 uses a very loose constraint
"he4rt/docs": ">=1", which allows any version from 1.0.0 onwards, including major version bumps that could introduce breaking changes. Consider using^1.0or^1to restrict to the 1.x version family.app-modules/docs/resources/views/home.blade.php (3)
29-35: Consider a more descriptive dark‑mode toggle labelThe button text is just “Toggle”, which is a bit vague and not ideal for accessibility. Consider something like “Toggle dark mode” (and/or an
aria-label) to make its purpose clearer, especially for screen readers.
36-39: Verify that$contentis safely sanitized before raw output
{!! $content !!}is appropriate for rendered Markdown/HTML, but it will allow any HTML/JS through. Please confirm that docs content only comes from trusted sources and/or passes through a sanitizer (e.g., a configured CommonMark pipeline with HTML filtering) before being injected here; otherwise this is an XSS risk.
41-93: TOC Alpine/IntersectionObserver logic is sound; you can optionally harden parsingThe TOC behavior (JSON‑encoded IDs,
x-datainit, and IntersectionObserver updates) looks correct and should work well. If you want extra robustness against future template changes, you could defensively parsedata-headings:- init() { - this.headings = JSON.parse(this.$el.dataset.headings) + init() { + try { + this.headings = JSON.parse(this.$el.dataset.headings || '[]') + } catch (e) { + this.headings = [] + }Not required, but it makes the component more resilient if the attribute is ever missing or malformed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
composer.lockis excluded by!**/*.lock
📒 Files selected for processing (3)
app-modules/docs/composer.json(1 hunks)app-modules/docs/resources/views/home.blade.php(1 hunks)composer.json(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- app-modules/docs/composer.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Perform Pest Tests / Run
🔇 Additional comments (1)
app-modules/docs/resources/views/home.blade.php (1)
1-28: Sidebar shell and navigation wiring look solidLayout usage and
$sidebariteration into groups/pages is clear and matches a typical docs nav structure; nothing blocking here.
GET - /docs/3.x (Base Docs)
GET - /docs/3.x/api (Scramble)
Summary by CodeRabbit
New Features
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.