collectivo-dev / collectivo

Collectivo is a modular open-source framework for buildig community platforms.

Home Page:https://docs.collectivo.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Collectivo

Collectivo is an open-source platform for collaboration, participation, and data management. The software is specifically designed to promote the active engagement and self-organization of members in community projects and organizations. With a modular structure, it can be easily customized to meet the needs of different users.

Collectivo is build on Nuxt, Directus, and (optionally) Keycloak. Features of the plattform are split into separate extensions, using Nuxt Layers. The software is designed to make it as easy as possible to develop additional extensions and integrate existing tools into the plattform.

If you are interested in using Collectivo or contributing to its development, please join our Discord server: https://discord.gg/42MWureAYW

Getting started

Installation

Install the following requirements:

Add the following to your etc/hosts file:

127.0.0.1 keycloak

Prepare the environment and start up a development server:

cp .env.example .env
pnpm install
docker compose up -d
pnpm dev

In a separate terminal, run the following to apply migrations and example data:

pnpm seed

Go back to the previous terminal (from pnpm dev) to see the migration logs.

The following services should now be available:

Log in with the following example users:

Configuration

  • Internationalization (see nuxt/i18n)
    • Change the default language: add i18n: {defaultLocale: 'en'} to nuxt.config.ts.

Migrations

Migrations between schemas can be run via the Nuxt API endpoint /api/migrate/. Extensions can define a schema for each version. E.g. a schema can be for version 0.0.1 of the core extension collectivo. A migration script can be run both before and after applying each schema version.

Migration flow

Migration requests must be authorized with the NUXT_API_TOKEN from .env.

The following parameters can be passed:

  • extension (string) - Apply migrations of a specific extension. If not given, all extensions will be migrated.
  • version (string) - Apply schemas towards specified version. If not given, migration will run up to the latest version.
  • examples (boolean) - Create example data (default false).
  • isolated (boolean) - Apply only the specified schema (if version is passed) or example data (if no version passed).

Here is an example to prepare a new system for local development (the same code is run by pnpm seed):

curl --header "Authorization: badToken" --request POST "http://localhost:3000/api/migrate/?examples=true"

This cURL command can also imported in an HTTP client like Postman.

Migration logs can be found in the nuxt terminal.

Troubleshooting

  • To reset the database, delete the volume of the directus-db database

Development guide

Overview

The repository is structured as follows:

  • collectivo - Modular frontend & Nuxt API for migrations
    • app - A container to run collectivo
    • collectivo - Core functionalities
    • extensions - Optional modules
      • memberships - Manage memberships of an organization
  • directus - Database, REST/GraphQL API, & Admin app
  • keycloak - Authentication

Creating an extension

  • Decide on a name for your extension, e.g. my-extension.
  • Create a fork of this repository
  • Create a new extension in collectivo/extensions/my-extension/.
    • Option 1: Copy the example from collectivo/extensions/example/.
    • Option 2: Create a new Nuxt Layer.
  • Configure my-extension/package.json.
    • Define a package name for your extension. We recommend to start the name with collectivo to make it easier to find, e.g. collectivo-my-extension.
    • Adding "@collectivo/collectivo": "workspace:*" to your dependencies gives you access to the types and functions of collectivo. (see workspace)
  • Configure my-extension/nuxt.config.ts.
    • To add collectivo, add extends: ["@collectivo/collectivo"] (see Nuxt Layer).
  • Register your extension on the backend (see registerExtension)
    • Here, you can set the name of your extension that should be used in the database. The name should not include underscores, e.g. myExtension.
  • Add your package to the development app
    • Add your package name to dependencies in collectivo/app/package.json, with the version being "workspace:*"
    • Add the package name to extends in collectivo/app/nuxt.config.ts.
    • Run pnpm i to connect the packages.
  • Create a database schema for your extension (see initschema).
  • Create frontend components for your extension (see Frontend API)
  • Follow installation to start the development app.

Adding a database schema

An extension can define a database schema

Note that database collections and fields should start with the name of the extension followed by an underscore to avoid name conflicts with other extensions. E.g. myExtension_myCollection and myExtension_myField.

Exceptions are the following system fields:

  • id
  • user_created
  • user_updated
  • date_created
  • date_updated
  • sort

Best practices

  • Regularly sync your fork with the upstream repository.
  • To update dependencies, run pnpm update collectivo/extensions/my-extension -L
  • You can also add fields to collections that are not part of your extensions, like directus_users.
  • To publish your extension, run pnpm publish collectivo/extensions/my-extension --access=public --dry-run (remove --dry-run after checking that everything is correct)
  • The example extension is licensed under public domain. You can choose your own license for your extension, it does not have to be the same as collectivo.

Unit testing

  • To run unit tests, use: pnpm test

Linting

  • To run linting checks, use: pnpm lint
  • To apply linting to all files, use: pnpm lint:fix

Formatting

  • To run formatting checks, use: pnpm format
  • To apply formatting to all files, use: pnpm format:fix

Workspace

Collectivo uses a pnpm workspace to manage multiple packages in a single repository. This allows you to declare dependencies to other packages in the workspace with package-name: "workspace:*". If you publish your package, the workspace "workspace:*" will be replaced with the current version of the depedency.

Theme

Collectivo uses tailwindcss and nuxt-ui for styling and components. The theme can be adapted in tailwind.config.ts and app.config.ts.

Authentication

Collectivo authenticated through directus. To protect pages, add the following middleware to the setup script. If keycloak is used, this will forward people directly to keycloak, using Directus' seamless SSO feature.

definePageMeta({
  middleware: ["auth"],
});

Icons

Collectivo uses nuxt-ui and Iconify to load icons. They have to be defined as i-{collection_name}-{icon_name}.

By default, Collectivo loads the following to icon libraries:

Additional libraries can be loaded in nuxt.config.ts.

API Reference

Frontend

The following composables are available for frontend development.

setCollectivoTitle

setCollectivoTitle(title: string)

Use in a page to set a page title for both the visible header and the metadata.

useDirectus

useDirectus(): DirectusClient

Access the directus client to interact with the database.

useCollectivoUser

useCollectivoUser(): UserStore

Store for data of the currently authenticated user, with the following attributes:

  • data: CollectivoUser | null
  • inputs: CollectivoUserInput[] -> Can be used to add fields to the profile section
  • isAuthenticated: boolean
  • saving: boolean
  • loading: boolean
  • error: unknown
  • load: (force: boolean = false) => Promise<UserStore> -> Fetch user data
  • save: (data: CollectivoUser) => Promise<UserStore> -> Update user data

useCollectivoMenus

useCollectivoMenus(): Ref<CollectivoMenus>

This composable can be used to add or adapt menu items.

There are two menus in CollectivoMenus:

  • main: Shown for authenticated users.
  • public: Shown for unauthenticated users.

Attributes:

  • label: string - Will be shown next to the icon.
  • icon: string - Icon to be used (see icons)
  • to: string - A path like /my/path or https://externallink.com
  • external: boolan - If true, path will be interepreted as an external URL.
  • hideOnMobile: boolean - If true, item will not be shown on small screens.
  • target: string - Target attribute of the link.
  • click: Function - Click attribute of the link.
  • filter: (item: CollectivoMenuItem) => boolean - Show item only if this function returns true.

Here is an example of how to add a menu item to the main menu through a plugin:

// my-extension/plugins/setup.ts
export default defineNuxtPlugin(() => {
  const menu = useCollectivoMenus();
  menu.value.main.push({
    label: "My menu item",
    icon: "i-system-uicons-cubes",
    to: "/my/path",
    order: 100
  });
}

Backend

The following utility functions can be used for server-side scripts (within /my-extension/server/)

registerExtension

registerExtension({name: string, description:string, version:string, schemas:ExtensionSchema[], examples: ()=>Promise<void>})

Registers a function within the runtime of the backend server, being able to multiple schemas for different versions of the extension as well as a function to create example data.

Should be used within a server plugin as follows:

// my-extension/server/plugins/registerExtension.ts
import pkg from "../../package.json";
import examples from "../examples/examples";
import mySchema from "../schemas/mySchema";
export default defineNitroPlugin(() => {
  registerExtension({
    name: "myExtension",
    description: pkg.description,
    version: pkg.version,
    schemas: [mySchema],
    examples: examples,
  });
});

initSchema

initSchema(extension: string, version: string, options: ExtensionSchemaOptions): ExtensionSchema

Initiates a new ExtensionSchema that can be used to define the database structure and migrations of your extension (see migrations).

Can be applied as follows and added to registerExtension:

// my-extension/server/schemas/mySchema.ts
const schema = initSchema("myExtension", "0.0.1");

export default schema;

ExtensionSchema

This class has the following attributes:

And the following methods:

  • createO2MRelation() - Utility method to create a One-to-Many relationship
  • createM2MRelation() - Utility method to create a Many-to_many relationship
  • createM2ARelation() - Utility method to create a Many-to-Any relationship

ExtensionDependency

This type can be used to define dependencies of a schema on another extension.

Attributes:

  • extension: String. The extension that the schema depends on.
  • version: String. The semantic version of the extension that the schema depends on.

DirectusFlowWrapper

This type can be used to construct directus flows in a schema.

Attributes:

  • flow: Partial<DirectusFlow<<any>> - this will define the trigger, see directus flow
  • firstOperation: string - key of the initial operation to be performed
  • operations: DirectusOperationWrapper[] - define a list of connected operations

DirectusOperationWrapper

This type can be used to define operations within DirectusFlowWrapper.

Attributes:

  • operation: Partial<DirectusOperation<<any>> - see directus operation
  • resolve: string - key of the operation to execute when this one is resolved
  • reject: string - key of the operation to execute when this one is rejected

useDirectusAdmin

useDirectusAdmin(): DirectusClient

Access the directus client with admin access.

logger

You can use winston to write information to the nuxt logs (console.log will not appear in production), e.g.:

logger.info("Hello world!");

About

Collectivo is a modular open-source framework for buildig community platforms.

https://docs.collectivo.io

License:GNU Affero General Public License v3.0


Languages

Language:TypeScript 70.7%Language:Vue 22.2%Language:JavaScript 6.6%Language:Dockerfile 0.3%Language:CSS 0.1%Language:HTML 0.1%