{"id":19212337,"url":"https://github.com/leafo/lapis-community","last_synced_at":"2026-02-23T15:33:06.574Z","repository":{"id":22331829,"uuid":"25667359","full_name":"leafo/lapis-community","owner":"leafo","description":"Pluggable message board for Lapis powered websites","archived":false,"fork":false,"pushed_at":"2024-08-09T20:39:42.000Z","size":1540,"stargazers_count":48,"open_issues_count":5,"forks_count":4,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-10-26T05:40:26.697Z","etag":null,"topics":["lapis","moonscript"],"latest_commit_sha":null,"homepage":"","language":"MoonScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/leafo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":["leafo"]}},"created_at":"2014-10-24T02:16:16.000Z","updated_at":"2025-05-27T06:56:28.000Z","dependencies_parsed_at":"2024-08-09T21:48:02.152Z","dependency_job_id":"2ec5bfbf-7f75-4e23-b961-ae143e17fd33","html_url":"https://github.com/leafo/lapis-community","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"purl":"pkg:github/leafo/lapis-community","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-community","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-community/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-community/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-community/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/leafo","download_url":"https://codeload.github.com/leafo/lapis-community/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/leafo%2Flapis-community/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29746570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T07:44:07.782Z","status":"ssl_error","status_checked_at":"2026-02-23T07:44:07.432Z","response_time":90,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["lapis","moonscript"],"created_at":"2024-11-09T13:46:32.921Z","updated_at":"2026-02-23T15:33:06.546Z","avatar_url":"https://github.com/leafo.png","language":"MoonScript","funding_links":["https://github.com/sponsors/leafo"],"categories":[],"sub_categories":[],"readme":"# lapis-community\n\nA drop in, full featured community and comment system for Lapis projects.\n\n![test](https://github.com/leafo/lapis-community/workflows/test/badge.svg)\n\nExample community: https://itch.io/community\n\nOn [itch.io](https://itch.io) every single community, message board, comment\nthread is powered by `lapis-community`. It's suitable for managing many\ndifferent sub communities with distinct moderators and roles.\n\n## Note on versioning\n\nThis project uses a 3 part version: `X.X.X`, which can be interpreted as\n`{major}.{schema}.{minor}`.\n\nThe *schema* version number is incremented if the database schema is updated in\nsome way. This update will include a corresponding database migration that\nmatches the number. These changes may also include changes to the code\ninterfaces. Read the change-log for notes about how to work with the update.\n\nIn your own Lapis app, you can assert that migrations up to a certain version\nare run by writing a migration that looks like: (where 42 is an example schema version)\n\n```moonscript\n=\u003e require(\"community.schema\").run_migrations 42\n```\n\nThe *minor* version number is incremented for bug fixes/minor changes that will\ncontinue to operate on the same schema. No significant changes to code\ninterfaces are made.\n\nThe *major* version will only be incremented if the project is rewritten or\nthere are substantial breaking changes such that require to concurrent versions\nof the library.\n\n## How it works\n\n`lapis-community` provides a collection of *Models* and *Flows* for a database\nbacked message board. It includes the application layer (aka server side logic)\nfor interacting with the community using *Flows*. A *Flow* is a class that\ngroups common functionality into a single module that works on top of the Lapis\naction/request interface.\n\nNo views are provided (excluding some simple examples) as this is typically the\npart of the message board that the implementing site will want to customize.\n\nThe following features are included:\n\n* Topics\n  * Sticky, Locked, and Archived topics\n  * Threaded replies\n  * Post content can be HTML or markdown\n  * Moderation events (e.g. *Moderator locked this topic*)\n  * Mentioning other accounts with `@`\n  * Efficient pagination of very large topics\n  * Soft deletion of replies allows for nested replies to be be lost when post is deleted\n  * Voting options for replies: up \u0026 down, up only, no voting\n  * Reply edit history\n  * Topics tags (defined on the category)\n  * Pinned replies\n* Categories (for organizing topics)\n  * Can be nested\n    * *Directory* categories can be used to organize sub-categories without allowing direct topics\n  * Categories can individually have title, description, rules along with enforced restrictions for posts\n  * Category options can be inherited from their parents when nested\n  * Topic sorting rules per category (by votes, by date, etc.)\n  * Categories can be configured to be \"members-only\"\n    * Membership status is inherited by the category hierarchy, so nested categories automatically will grant access to a user if they are a member of a higher up category\n* Pending Posts\n  * New topics or posts can be marked as pending, and will need to be approved by a moderator before they are published\n  * Moderators can set global rules on categories to force every post to go into pending\n  * Implementing community can define own rules around what posts are put into pending queue, eg. from spam detector\n* Category groups\n  * A way to apply moderation rules across many categories that aren't related in a tree hierarchy\n* Moderators\n  * A category can define a list of special user accounts that have extended permissions over the posts \u0026 topics in that category\n  * Moderators will have control over the entire category hierarchy below where their role is defined, and a moderator can be created at any level of the hierarchy\n  * Moderators can not add new moderators unless they are marked as \"admin\" moderator\n  * Moderator must approve the request to become moderator, to prevent random user from adding others as moderators indiscriminately\n* Post Reporting\n  * Any user can create a report on a post if they feel it violates the community rules in some way\n  * The report will make a copy of the post, in case the post is deleted, so admins \u0026 moderators can still review that account for violation\n* Community stats aggregated per user, per topic, per category\n* Visibility tracking\n  * Tracks if individual user has yet to see a topic, or topic has unseen replies\n* Activity logs\n  * Keep an auditable history of all actions on the community\n  * Separate moderator logs indexed per category\n* Bookmarks\n  * A way to save topics for viewing later\n* Subscriptions\n  * For generating notifications when topics are updated\n* Search index\n  * Full-text search index on replies and topics\n* Blocks\n  * An account can block another account to not see their posts\n* Bans\n  * Moderators can ban accounts from posting or seeing their category\n* Warnings\n  * A warning can be created on an account to either block or force all posts to go into pending for some duration\n  * The warning contains a message about what rule was violated\n  * The warning duration only starts after it has been viewed for the first time\n\nThe database schema is managed by the Lapis migration system, using a scoped\nset of migrations. Upgrading the database for a new version of\n`lapis-community` is as simple as installing the latest version and running the\nmigration within your own migrations file.\n\n\n```moonscript\n-- migrations.moon\n{\n  -- ...\n\n  =\u003e require(\"community.schema\").run_migrations!\n}\n```\n\n### Extension interface\n\nNo community software perfectly matches the requirements of a particular\nwebsite or app. `lapis-community` is built with extensibility in mind. You can\ncustomize how things work by either replacing build-in logic, or appending\nadditional logic.\n\n\u003e **Example**\n\u003e * replacing: using your own models to control who can moderate posts\n\u003e * appending: using both the built in moderator system and your own models to control who can moderate posts.\n\n* **Flows** - Since a *Flow* is a class, you can subclass the flow and replace\n  methods to change how common operations work\n* **Models** - The model loader will attempt to load version of the model from\n  your own local models directory before loading the built in one. This can be\n  used to either subclass (or replace!) build in models to add additional\n  relations and functionality\n  * Models have special `on_*_callback` methods can are designed to be replaced\n    in a subclass to provide additional functionality in response to events in\n    the community\n\n### No presentation layer included\n\n`lapis-community` exposes the models for you to use directly. You can decide\nhow to format the data within when rendering views, whether that's passing them\ndown server-side rendered templates, or converting to JSON for client-side\nJavaScript templates.\n\nThere are flows, however, for fetching the models and preloading all the\nnecessary data. For example, loading the threaded replies for a particular\ntopic on a particular page.\n\n## Where it's used\n\n* [itch.io](https://itch.io): global message board, game communities, every single comment thread eg. https://itch.io/community\n* [streak.club](https://streak.club): streak message boards\n\n## Documentation\n\n*Coming soon*\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafo%2Flapis-community","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fleafo%2Flapis-community","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fleafo%2Flapis-community/lists"}