I still remember the Friday when a simple approval stalled right before a product launch. Everyone blamed the server. The real issue was a missing property in the workflow model that the task form expected. One tiny mismatch and the whole queue froze. That night taught me this: Alfresco workflows are forgiving until they are not. If you are customizing, you need a clear map of models, forms, and process variables. With that map, a stuck instance becomes a quick fix. Without it, you are in the dark poking at logs while people refresh Share every five minutes.
Practical notes for customizing Alfresco workflows
Start with language. Your content model and your process variables should tell the same story. Keep property names consistent and readable across your BPMN, your model XML, and your forms. If your task needs a due date, define it once, with one name, then reuse that name in the form config and in service tasks. Map business fields to aspects on the document rather than stuffing everything into the process instance. This keeps history clean and future friendly. Add constraints for enums and dates so validation happens before people click Complete. Save booleans for flags that truly control flow. And please, do not overload the package node with random properties. That way lies confusion.
Share is where users live, so invest there. Use share-config-custom to shape start forms and task forms. Keep forms short and dependable and reserve conditionals for things that really change the decision. If two groups use the same task, split the form into tabs with clear labels and help text. Try not to hide required fields behind clever rules. For outcomes, align button labels with sequence flows in your BPMN. Users read buttons. The engine reads your expressions. Keep both in sync. If you need extra routing, add a simple decision task rather than cramming logic into a script field. It is easier to debug a visible step than a clever trick buried in a form evaluator.
Pick the right place for automation. Small glue belongs in JavaScript listeners in the repository. Heavy lifting and external services belong in Java delegates. A quick filename tweak or an aspect toggle is fine in script. A payment call or a CRM update should not run inside the same transaction as your task completion. Use a queue or call out with retry. For emails, keep your Freemarker templates in the Data Dictionary so content people can tweak copy without deploying. Timers are your friend for SLAs. A boundary timer that triggers an escalated path is usually better than a nightly job that scans for late tasks. Fewer moving parts, clearer intent.
Stay close to the engine. The Activiti BPMN modeler exported from your favorite editor should marry well with Alfresco, but keep an eye on names. Every field you reference in an expression must exist at runtime. Loggers help. Turn up org.alfresco.repo.workflow and org.activiti when testing. Keep versions of your process key and do not overwrite a live definition with a silent change. If you must change a running process, add a new version and let old instances finish naturally. In dev, use the Node Browser to peek at variables and the workflow console to cancel zombie instances. It beats guessing. A simple test process with one user task and one script task can save hours on the real one.
Security deserves its own pass. Assignment is more than picking a person. Swimlanes and candidate groups can mirror your LDAP groups, but be careful when groups shift. Favor group assignment with claim rather than pushing every task straight to a person. It keeps work visible and avoids dead ends when someone leaves. For content permissions, change roles on the document as it moves through key steps rather than opening everything at start. A reviewer does not always need write access. Use aspects for state and permissions for control. Keep your email messages short and clear and link directly to the task. People act faster when the path is one click and the form loads with only what they need.
Summary
Customizing Alfresco workflows pays off when you treat the system as a set of small agreements. The model agrees with the forms. The forms agree with the BPMN. The BPMN agrees with the logs and the way people actually work. Keep names consistent. Put the right code in the right layer. Use timers for predictable escalations and templates for friendly messages. Version your processes and watch your variables. If something stalls, check the form config first, then the model, then the workflow instance. Most surprises come from a missing property or a mismatched name. Ship a small workflow, learn, then add the fancy parts. That Friday night, the fix was one property and a restart. It should not have taken hours. Yours will not if you keep these notes close.